Full Code of tsenart/vegeta for AI

master cf5811269046 cached
70 files
742.9 KB
330.7k tokens
354 symbols
1 requests
Download .txt
Showing preview only (772K chars total). Download the full file or copy to clipboard to get everything.
Repository: tsenart/vegeta
Branch: master
Commit: cf5811269046
Files: 70
Total size: 742.9 KB

Directory structure:
gitextract_wz3_b8r2/

├── .github/
│   ├── CODEOWNERS
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── CHANGELOG
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── attack.go
├── attack_nonwindows.go
├── attack_test.go
├── attack_windows.go
├── dump.go
├── encode.go
├── file.go
├── flags.go
├── go.mod
├── go.sum
├── internal/
│   ├── cmd/
│   │   ├── echosrv/
│   │   │   └── main.go
│   │   └── jsonschema/
│   │       └── main.go
│   └── resolver/
│       ├── resolver.go
│       └── resolver_test.go
├── lib/
│   ├── attack.go
│   ├── attack_fuzz.go
│   ├── attack_test.go
│   ├── histogram.go
│   ├── histogram_test.go
│   ├── lttb/
│   │   ├── lttb.go
│   │   └── lttb_test.go
│   ├── metrics.go
│   ├── metrics_test.go
│   ├── pacer.go
│   ├── pacer_test.go
│   ├── plot/
│   │   ├── assets/
│   │   │   ├── VERSIONS
│   │   │   ├── plot.html.tpl
│   │   │   └── uplot-plugins.js
│   │   ├── assets.go
│   │   ├── embed.go
│   │   ├── plot.go
│   │   ├── plot_test.go
│   │   ├── testdata/
│   │   │   └── TestPlot.golden.html
│   │   └── timeseries.go
│   ├── prom/
│   │   ├── grafana.json
│   │   ├── prom.go
│   │   └── prom_test.go
│   ├── reporters.go
│   ├── results.go
│   ├── results_easyjson.go
│   ├── results_fuzz.go
│   ├── results_test.go
│   ├── target.schema.json
│   ├── targets.go
│   ├── targets_easyjson.go
│   ├── targets_fuzz.go
│   ├── targets_test.go
│   └── util_fuzz.go
├── main.go
├── plot.go
├── report.go
├── report_nonwindows.go
├── report_windows.go
└── scripts/
    └── load-ramping/
        ├── README.md
        ├── ramp-requests.plt
        └── ramp-requests.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/CODEOWNERS
================================================
* @tsenart @xla

================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing

Non trivial changes should be discussed with the project maintainers by
opening a [Feature Request](https://github.com/tsenart/vegeta/issues/new?template=feature_request.md),
clearly explaining rationale, background and possible implementation ideas.
Feel free to use to provide code in such discussions.

## Implementation

Work should happen in an open pull request with a WIP label
which gives visibility to the development process and provides
continuous integration feedback.

The pull request description must be well written and provide the necessary
context and background for review. If there's a proposal issue, it must be
referenced. When ready, remove the WIP label assign the PR a reviewer who will
review your PR.


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: 🐛  Bug Report
about: Report a bug to help Vegeta improve.
---

<!-- ⚠️ If you do not respect this template your bug report issue will be closed. -->

#### Version and Runtime

```
Paste the output of `vegeta -version` here.
If you are not running the latest version of Vegeta, please try upgrading because your issue may have already been fixed.
```

#### Expected Behaviour

<!-- What did you expect to see?  -->

#### Actual Behaviour

<!-- What did you see instead?  -->

#### Steps to Reproduce

<!-- Please list the full steps required to reproduce the bug. -->

1. Step 1
1. Step N

#### Additional Context

<!--

Are there any other related GitHub issues (open or closed) or Pull Requests that should be linked here?
Is there anything atypical to be known about your situation?
Anything else?

-->


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: 🚀  Feature Request
about: Propose a change to Vegeta💡!
---

<!-- ⚠️ If you do not respect this template your issue will be closed. -->
<!-- ⚠️ Make sure to browse the opened and closed issues before submit your issue. -->

#### Proposal

<!-- Write your feature request in the form of a proposal to be considered for implementation -->

#### Background

<!-- Describe the background problem or need that led to this feature request -->

#### Workarounds

<!-- Are there any current workarounds that you're using that others in similar positions should know about? -->

================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: ❓ Question
about: Ask a question that isn't a feature request nor a bug report.
---

#### Question

================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
#### Background

<!-- Required background information to understand the PR. Link here any related issues. -->

#### Checklist

- [ ] Git commit messages conform to [community standards](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
- [ ] Each Git commit represents meaningful milestones or atomic units of work.
- [ ] Changed or added code is covered by appropriate tests.


================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "gomod"
    directory: "/" 
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
  push:
    tags:
      - "v*.*.*"
    branches:
      - master
  pull_request:
    types: [opened, synchronize, reopened]
  workflow_dispatch:
    inputs:
      version:
        description: "Release version"
        required: true

jobs:
  qa:
    name: Quality Assurance
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.22"

      - name: Format Check
        run: |
          set -euo pipefail
          go install golang.org/x/tools/cmd/goimports@latest
          goimports -w .
          git diff --exit-code

      - name: Vet
        run: go vet ./...

      - name: Test
        run: go test -race ./...

  build:
    name: Build
    if: startsWith(github.ref, 'refs/tags/v')
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target:
          - "windows/amd64"
          - "windows/386"
          - "windows/arm64"
          - "linux/amd64"
          - "linux/386"
          - "linux/arm64"
          - "linux/arm"
          - "darwin/amd64"
          - "darwin/arm64"
          - "freebsd/386"
          - "freebsd/amd64"
          - "freebsd/arm"
          - "openbsd/amd64"
          - "openbsd/arm64"
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: "1.22"

      - name: Set up GOOS and GOARCH
        id: setup_env
        run: |
          echo "goos=$(echo ${{ matrix.target }} | cut -d'/' -f1)" >> $GITHUB_OUTPUT
          echo "goarch=$(echo ${{ matrix.target }} | cut -d'/' -f2)" >> $GITHUB_OUTPUT

      - name: Build
        env:
          GOOS: ${{ steps.setup_env.outputs.goos }}
          GOARCH: ${{ steps.setup_env.outputs.goarch }}
        run: |
          set -euo pipefail

          make vegeta

          VERSION=${GITHUB_REF#refs/tags/v}
          NAME="vegeta_${VERSION}_${GOOS}_${GOARCH}"
          if [[ "$GOOS" != "windows" ]]; then
            tar -czf "$NAME.tar.gz" vegeta
          else
            zip "$NAME.zip" vegeta.exe
          fi

      - name: Upload Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: vegeta_${{ steps.setup_env.outputs.goos }}_${{ steps.setup_env.outputs.goarch }}
          path: |
            *.zip
            *.tar.gz

  release:
    name: Release
    if: startsWith(github.ref, 'refs/tags/v')
    needs: [qa, build]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Download Artifacts
        uses: actions/download-artifact@v4

      - name: Create checksums and sign them
        id: sign
        run: |
          set -euo pipefail

          mkdir dist
          mv vegeta*/* dist/
          cd dist

          VERSION=${GITHUB_REF#refs/tags/v}
          CHECKSUMS=vegeta_${VERSION}_checksums.txt
          sha256sum * > $CHECKSUMS

          echo "${{ secrets.VEGETA_GPG_KEY }}" | gpg --batch --yes --pinentry-mode loopback --import
          gpg --export --armor > vegeta_${VERSION}_pubkey.asc
          gpg --detach-sign -a $CHECKSUMS

          echo "name=${VERSION}" >> $GITHUB_OUTPUT

      - name: Generate release notes
        id: release_notes
        run: |
          set -x
          set -euo pipefail

          CURRENT_VERSION=${GITHUB_REF#refs/tags/}
          PREV_VERSION=$(git describe --tags --abbrev=0 $CURRENT_VERSION^)
          RELEASE_NOTES=${{ github.workspace }}/release-notes.txt

          printf "## Changelog\n\n" > $RELEASE_NOTES
          git log ${PREV_VERSION}..${CURRENT_VERSION} --oneline --abbrev-commit >> $RELEASE_NOTES
          cat $RELEASE_NOTES

      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          name: ${{ steps.sign.outputs.version }}
          body_path: ${{ github.workspace }}/release-notes.txt
          files: |
            dist/*
          tag_name: ${{ steps.sign.outputs.version }}
          draft: true
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}


================================================
FILE: .gitignore
================================================
# 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

vegeta
vegeta.test
vegeta-*.tar.gz
lib/lib.test
dist
vendor

*.gob
*.lz

.DS_Store


================================================
FILE: CHANGELOG
================================================
2018-05-18: v7.0.0
  Include response body in hit results (#279)
  Added support for h2c requests (HTTP/2 without TLS) (#261)
  Prevent "null" Metrics.Errors JSON encoding (#277)
  Add option to override HTTP Proxy on Attacker (#234)

2017-03-19: v6.3.0
  Mark responses as success in no redirect following mode (#222)

2017-03-04: v6.2.0
  Allow any upper-case ASCII word to be an HTTP method (#217)
  Correctly compute Metrics.Rate with sub-second duration results (#208)

2016-08-26: v6.1.1
  Respect case sensitivity in target file header names (#195, #191)

2016-04-03: v6.1.0
  Add HTTP2 support

2015-11-27: v6.0.0
  Insecure attack flag (#160)
  Client certificates (#156)
  Infinite attacks (#155)
  Allow empty lines between targets (#147)

2015-09-19: v5.9.0
  Bounded memory streaming reporters (#136)

2015-09-04: v5.8.1
  Fix support for DELETE methods in targets

2015-08-11: v5.8.0
  Change reporters quantile estimation method to match R's 8th type.

2015-05-23: v5.7.1
  Revert end-to-end attack timeout change

2015-05-23: v5.7.0
  Allow case sensitve headers in attacks

2015-04-15: v5.6.3
  Expose connections flag in the attack command
  Add global cpu and heap profiling flags
  Measure actual attack rate and print it in relevant reporters
  Major performance improvements that allow much higher attack rates

2015-04-02: v5.6.2
  Update dygraph to latest version
  Improve plot reporter screenshot rendering by using html2canvas.js
  Improve plot reporter performance

2015-03-23: v5.6.1
  Allow spaces in hist reporter flag format

2015-03-12: v5.6.0
  Set default dumper to "json" in the dump command.
  Add --version to global vegeta command flags.
  Fix response body leak regression introduced in v5.5.3.

2015-03-11: v5.5.3
  Always read response bodies for each request.
  Homebrew install instructions.

2015-01-3: v5.5.2
  Refactor core request logic and simplify tests with a 4x speedup.

2015-01-2: v5.5.1
  Treat bad status codes as errors.

2014-11-21: v5.5.0
  Implement dump command with CSV and JSON record format.
  Optionally ignore redirects and treat them as successes.

2014-11-16: v5.4.0
  Add histogram reporter to the report command.

2014-11-16: v5.3.0
  Add support for extended targets dsl that supports per-target headers and body.
  Target file comments support has been removed.

2014-11-7: v5.2.0
  Don't treat 3xx status codes as errors.
  Add -keepalive flag to the attack command.

2014-11-3: v5.1.1
  Add FreeBSD and Windows releases.
  Fix non termination bug in the report command. #85


================================================
FILE: Dockerfile
================================================
FROM golang:1.20-alpine3.18 AS BUILD

RUN apk add make build-base git

WORKDIR /vegeta

# cache dependencies
ADD go.mod /vegeta
ADD go.sum /vegeta
RUN go mod download

ADD . /vegeta

RUN make generate
RUN make vegeta

FROM alpine:3.18.0

COPY --from=BUILD /vegeta/vegeta /bin/vegeta

ENTRYPOINT ["vegeta"]


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2013-2023 Tomás Senart

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.


================================================
FILE: Makefile
================================================
COMMIT=$(shell git rev-parse HEAD)
VERSION=$(shell git describe --tags --exact-match --always)
DATE=$(shell date +'%FT%TZ%z')

vegeta: generate
	CGO_ENABLED=0 go build -v -a -tags=netgo \
  	-ldflags '-s -w -extldflags "-static" -X main.Version=$(VERSION) -X main.Commit=$(COMMIT) -X main.Date=$(DATE)'

generate: GOARCH := $(shell go env GOHOSTARCH)
generate: GOOS := $(shell go env GOHOSTOS)
generate:
	go install github.com/mailru/easyjson/...@latest
	go get github.com/shurcooL/vfsgen
	go install github.com/shurcooL/vfsgen/...@latest
	go generate ./...


================================================
FILE: README.md
================================================
# Vegeta [![Build Status](https://github.com/tsenart/vegeta/workflows/CI/badge.svg)](https://github.com/tsenart/vegeta/actions) [![Go Report Card](https://goreportcard.com/badge/github.com/tsenart/vegeta)](https://goreportcard.com/report/github.com/tsenart/vegeta) [![PkgGoDev](https://pkg.go.dev/badge/github.com/tsenart/vegeta/v12/lib)](https://pkg.go.dev/github.com/tsenart/vegeta/v12/lib) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tsenart/vegeta?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Donate](https://img.shields.io/badge/donate-bitcoin-yellow.svg)](#donate)

Vegeta is a versatile HTTP load testing tool built out of a need to drill
HTTP services with a constant request rate. [It's over 9000!](https://en.wikipedia.org/wiki/It's_Over_9000)

![Vegeta](assets/hero.png)

## Features

- Usable as a command line tool and a Go library.
- CLI designed with UNIX composability in mind.
- [Avoids](https://github.com/tsenart/vegeta/pull/92/files#r20198929) nasty [Coordinated Omission](http://highscalability.com/blog/2015/10/5/your-load-generator-is-probably-lying-to-you-take-the-red-pi.html).
- Extensive reporting functionality.
- Simple to use for [distributed load testing](https://kubernetes.io/blog/2015/11/one-million-requests-per-second-dependable-and-dynamic-distributed-systems-at-scale/).
- Easy to install and run (static binary, package managers, etc).

## Install

### Pre-compiled executables

Get them [here](http://github.com/tsenart/vegeta/releases).

### macOS

You can install Vegeta using the [Homebrew](https://github.com/Homebrew/homebrew/):

```shell
$ brew update && brew install vegeta
```

Or with [MacPorts](https://www.macports.org/):

```shell
$ port install vegeta
```

### Arch Linux

```shell
$ pacman -S vegeta
```

### FreeBSD

On FreeBSD you can install Vegeta with the built in package manager because there is a [Vegeta Package](https://www.freshports.org/benchmarks/vegeta) available.

```shell
$ pkg install vegeta
```

### Source

```shell
git clone https://github.com/tsenart/vegeta
cd vegeta
make vegeta
mv vegeta ~/bin # Or elsewhere, up to you.
```

## Versioning

Both the library and the CLI are versioned with [SemVer v2.0.0](https://semver.org/spec/v2.0.0.html).

After [v8.0.0](https://github.com/tsenart/vegeta/tree/v8.0.0), the two components
are versioned separately to better isolate breaking changes to each.

CLI releases are tagged with `cli/vMAJOR.MINOR.PATCH` and published on the [GitHub releases page](https://github.com/tsenart/vegeta/releases).
As for the library, new versions are tagged with both `lib/vMAJOR.MINOR.PATCH` and `vMAJOR.MINOR.PATCH`.
The latter tag is required for compatibility with `go mod`.

## Contributing

See [CONTRIBUTING.md](.github/CONTRIBUTING.md).

## Usage manual

```console
Usage: vegeta [global flags] <command> [command flags]

global flags:
  -cpus int
    	Number of CPUs to use (default = number of cpus)
  -profile string
    	Enable profiling of [cpu, heap]
  -version
    	Print version and exit

attack command:
  -body string
    	Requests body file
  -cert string
    	TLS client PEM encoded certificate file
  -chunked
    	Send body with chunked transfer encoding
  -connect-to value
    	A mapping of (ip|host):port to use instead of a target URL's (ip|host):port. Can be repeated multiple times.
    	Identical src:port with different dst:port will round-robin over the different dst:port pairs.
    	Example: google.com:80:localhost:6060
  -connections int
    	Max open idle connections per target host (default 10000)
  -dns-ttl value
    	Cache DNS lookups for the given duration [-1 = disabled, 0 = forever] (default 0s)
  -duration duration
    	Duration of the test [0 = forever]
  -format string
    	Targets format [http, json] (default "http")
  -h2c
    	Send HTTP/2 requests without TLS encryption
  -header value
    	Request header
  -http2
    	Send HTTP/2 requests when supported by the server (default true)
  -insecure
    	Ignore invalid server TLS certificates
  -keepalive
    	Use persistent connections (default true)
  -key string
    	TLS client PEM encoded private key file
  -laddr value
    	Local IP address (default 0.0.0.0)
  -lazy
    	Read targets lazily
  -max-body value
    	Maximum number of bytes to capture from response bodies. [-1 = no limit] (default -1)
  -max-connections int
    	Max connections per target host
  -max-workers uint
    	Maximum number of workers (default 18446744073709551615)
  -name string
    	Attack name
  -output string
    	Output file (default "stdout")
  -prometheus-addr string
    	Prometheus exporter listen address [empty = disabled]. Example: 0.0.0.0:8880
  -proxy-header value
    	Proxy CONNECT header
  -rate value
    	Number of requests per time unit [0 = infinity] (default 50/1s)
  -redirects int
    	Number of redirects to follow. -1 will not follow but marks as success (default 10)
  -resolvers value
    	List of addresses (ip:port) to use for DNS resolution. Disables use of local system DNS. (comma separated list)
  -root-certs value
    	TLS root certificate files (comma separated list)
  -session-tickets
    	Enable TLS session resumption using session tickets
  -targets string
    	Targets file (default "stdin")
  -timeout duration
    	Requests timeout (default 30s)
  -unix-socket string
    	Connect over a unix socket. This overrides the host address in target URLs
  -workers uint
    	Initial number of workers (default 10)

encode command:
  -output string
    	Output file (default "stdout")
  -to string
    	Output encoding [csv, gob, json] (default "json")

plot command:
  -output string
    	Output file (default "stdout")
  -threshold int
    	Threshold of data points above which series are downsampled. (default 4000)
  -title string
    	Title and header of the resulting HTML page (default "Vegeta Plot")

report command:
  -buckets string
    	Histogram buckets, e.g.: "[0,1ms,10ms]"
  -every duration
    	Report interval
  -output string
    	Output file (default "stdout")
  -type string
    	Report type to generate [text, json, hist[buckets], hdrplot] (default "text")

examples:
  echo "GET http://localhost/" | vegeta attack -duration=5s | tee results.bin | vegeta report
  vegeta report -type=json results.bin > metrics.json
  cat results.bin | vegeta plot > plot.html
  cat results.bin | vegeta report -type="hist[0,100ms,200ms,300ms]"
```

#### `-cpus`

Specifies the number of CPUs to be used internally.
It defaults to the amount of CPUs available in the system.

#### `-profile`

Specifies which profiler to enable during execution. Both _cpu_ and
_heap_ profiles are supported. It defaults to none.

#### `-version`

Prints the version and exits.

### `attack` command

#### `-body`

Specifies the file whose content will be set as the body of every
request unless overridden per attack target, see `-targets`.

#### `-cert`

Specifies the PEM encoded TLS client certificate file to be used with HTTPS requests.
If `-key` isn't specified, it will be set to the value of this flag.

#### `-chunked`

Specifies whether to send request bodies with the chunked transfer encoding.

#### `-connections`

Specifies the maximum number of idle open connections per target host.

#### `-dns-ttl`

Specifies the duration to cache DNS lookups for. A zero value caches forever.
A negative value disables caching altogether.

#### `-max-connections`

Specifies the maximum number of connections per target host.

#### `-duration`

Specifies the amount of time to issue request to the targets.
The internal concurrency structure's setup has this value as a variable.
The actual run time of the test can be longer than specified due to the
responses delay. Use 0 for an infinite attack.

#### `-format`

Specifies the targets format to decode.

##### `json` format

The JSON format makes integration with programs that produce targets dynamically easier.
Each target is one JSON object in its own line. The method and url fields are required.
If present, the body field must be base64 encoded. The generated [JSON Schema](lib/target.schema.json)
defines the format in detail.

```bash
jq -ncM '{method: "GET", url: "http://goku", body: "Punch!" | @base64, header: {"Content-Type": ["text/plain"]}}' |
  vegeta attack -format=json -rate=100 | vegeta encode
```

##### `http` format

The http format almost resembles the plain-text HTTP message format defined in
[RFC 2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) but it
doesn't support in-line HTTP bodies, only references to files that are loaded and used
as request bodies (as exemplified below).

Although targets in this format can be produced by other programs, it was originally
meant to be used by people writing targets by hand for simple use cases.

Here are a few examples of valid targets files in the http format:

###### Simple targets

```
GET http://goku:9090/path/to/dragon?item=ball
GET http://user:password@goku:9090/path/to
HEAD http://goku:9090/path/to/success
```

###### Targets with custom headers

```
GET http://user:password@goku:9090/path/to
X-Account-ID: 8675309

DELETE http://goku:9090/path/to/remove
Confirmation-Token: 90215
Authorization: Token DEADBEEF
```

###### Targets with custom bodies

```
POST http://goku:9090/things
@/path/to/newthing.json

PATCH http://goku:9090/thing/71988591
@/path/to/thing-71988591.json
```

###### Targets with custom bodies and headers

```
POST http://goku:9090/things
X-Account-ID: 99
@/path/to/newthing.json
```

###### Add comments

Lines starting with `#` are ignored.

```
# get a dragon ball
GET http://goku:9090/path/to/dragon?item=ball
# specify a test account
X-Account-ID: 99
```

#### `-h2c`

Specifies that HTTP2 requests are to be sent over TCP without TLS encryption.

#### `-header`

Specifies a request header to be used in all targets defined, see `-targets`.
You can specify as many as needed by repeating the flag.

#### `-http2`

Specifies whether to enable HTTP/2 requests to servers which support it.

#### `-insecure`

Specifies whether to ignore invalid server TLS certificates.

#### `-keepalive`

Specifies whether to reuse TCP connections between HTTP requests.

#### `-key`

Specifies the PEM encoded TLS client certificate private key file to be
used with HTTPS requests.

#### `-laddr`

Specifies the local IP address to be used.

#### `-lazy`

Specifies whether to read the input targets lazily instead of eagerly.
This allows streaming targets into the attack command and reduces memory
footprint.
The trade-off is one of added latency in each hit against the targets.

#### `-max-body`

Specifies the maximum number of bytes to capture from the body of each
response. Remaining unread bytes will be fully read but discarded.
Set to -1 for no limit. It knows how to interpret values like these:

- `"10 MB"` -> `10MB`
- `"10240 g"` -> `10TB`
- `"2000"` -> `2000B`
- `"1tB"` -> `1TB`
- `"5 peta"` -> `5PB`
- `"28 kilobytes"` -> `28KB`
- `"1 gigabyte"` -> `1GB`

#### `-name`

Specifies the name of the attack to be recorded in responses.

#### `-output`

Specifies the output file to which the binary results will be written
to. Made to be piped to the report command input. Defaults to stdout.

#### `-rate`

Specifies the request rate per time unit to issue against
the targets. The actual request rate can vary slightly due to things like
garbage collection, but overall it should stay very close to the specified.
If no time unit is provided, 1s is used.

A `-rate` of `0` or `infinity` means vegeta will send requests as fast as possible.
Use together with `-max-workers` to model a fixed set of concurrent users sending
requests serially (i.e. waiting for a response before sending the next request).

Setting `-max-workers` to a very high number while setting `-rate=0` can result in
vegeta consuming too many resources and crashing. Use with care.

#### `-redirects`

Specifies the max number of redirects followed on each request. The
default is 10. When the value is -1, redirects are not followed but
the response is marked as successful.

#### `-resolvers`

Specifies custom DNS resolver addresses to use for name resolution instead of
the ones configured by the operating system. Works only on non Windows systems.

#### `-root-certs`

Specifies the trusted TLS root CAs certificate files as a comma separated
list. If unspecified, the default system CAs certificates will be used.

#### `-session-tickets`

Specifies whether to support TLS session resumption using session tickets.

#### `-targets`

Specifies the file from which to read targets, defaulting to stdin.
See the [`-format`](#-format) section to learn about the different target formats.

#### `-timeout`

Specifies the timeout for each request. A value of `0` disables timeouts.

#### `-workers`

Specifies the initial number of workers used in the attack. The actual
number of workers will increase if necessary in order to sustain the
requested rate, unless it'd go beyond `-max-workers`.

#### `-max-workers`

Specifies the maximum number of workers used in the attack. It can be used to
control the concurrency level used by an attack.

### `report` command

```console
Usage: vegeta report [options] [<file>...]

Outputs a report of attack results.

Arguments:
  <file>  A file with vegeta attack results encoded with one of
          the supported encodings (gob | json | csv) [default: stdin]

Options:
  --type    Which report type to generate (text | json | hist[buckets] | hdrplot).
            [default: text]

  --buckets Histogram buckets, e.g.: '[0,1ms,10ms]'

  --every   Write the report to --output at every given interval (e.g 100ms)
            The default of 0 means the report will only be written after
            all results have been processed. [default: 0]

  --output  Output file [default: stdout]

Examples:
  echo "GET http://:80" | vegeta attack -rate=10/s > results.gob
  echo "GET http://:80" | vegeta attack -rate=100/s | vegeta encode > results.json
  vegeta report results.*
```

#### `report -type=text`

```console
Requests      [total, rate, throughput] 1200, 120.00, 65.87
Duration      [total, attack, wait]     10.094965987s, 9.949883921s, 145.082066ms
Latencies     [min, mean, 50, 95, 99, max]  90.438129ms, 113.172398ms, 108.272568ms, 140.18235ms, 247.771566ms, 264.815246ms
Bytes In      [total, mean]             3714690, 3095.57
Bytes Out     [total, mean]             0, 0.00
Success       [ratio]                   55.42%
Status Codes  [code:count]              0:535  200:665
Error Set:
Get http://localhost:6060: dial tcp 127.0.0.1:6060: connection refused
Get http://localhost:6060: read tcp 127.0.0.1:6060: connection reset by peer
Get http://localhost:6060: dial tcp 127.0.0.1:6060: connection reset by peer
Get http://localhost:6060: write tcp 127.0.0.1:6060: broken pipe
Get http://localhost:6060: net/http: transport closed before response was received
Get http://localhost:6060: http: can't write HTTP request on broken connection
```

The `Requests` row shows:

- The `total` number of issued requests.
- The real request `rate` sustained during the `attack` period.
- The `throughput` of successful requests over the `total` period.

The `Duration` row shows:

- The `attack` time taken issuing all requests (`total` - `wait`)
- The `wait` time waiting for the response to the last issued request (`total` - `attack`)
- The `total` time taken in the attack (`attack` + `wait`)

Latency is the amount of time taken for a response to a request to be read (including the `-max-body` bytes from the response body).

- `min` is the minimum latency of all requests in an attack.
- `mean` is the [arithmetic mean / average](https://en.wikipedia.org/wiki/Arithmetic_mean) of the latencies of all requests in an attack.
- `50`, `90`, `95`, `99` are the 50th, 90th, 95th and 99th [percentiles](https://en.wikipedia.org/wiki/Percentile), respectively, of the latencies of all requests in an attack. To understand more about why these are useful, I recommend [this article](https://bravenewgeek.com/everything-you-know-about-latency-is-wrong/) from @tylertreat.
- `max` is the maximum latency of all requests in an attack.

The `Bytes In` and `Bytes Out` rows shows:

- The `total` number of bytes sent (out) or received (in) with the request or response bodies.
- The `mean` number of bytes sent (out) or received (in) with the request or response bodies.

The `Success` ratio shows the percentage of requests whose responses didn't error and had status codes between **200** and **400** (non-inclusive).

The `Status Codes` row shows a histogram of status codes. `0` status codes mean a request failed to be sent.

The `Error Set` shows a unique set of errors returned by all issued requests. These include requests that got non-successful response status code.

#### `report -type=json`

All duration like fields are in nanoseconds.

```json
{
  "latencies": {
    "total": 237119463,
    "mean": 2371194,
    "50th": 2854306,
    "90th": 3228223,
    "95th": 3478629,
    "99th": 3530000,
    "max": 3660505,
    "min": 1949582
  },
  "buckets": {
    "0": 9952,
    "1000000": 40,
    "2000000": 6,
    "3000000": 0,
    "4000000": 0,
    "5000000": 2
  },
  "bytes_in": {
    "total": 606700,
    "mean": 6067
  },
  "bytes_out": {
    "total": 0,
    "mean": 0
  },
  "earliest": "2015-09-19T14:45:50.645818631+02:00",
  "latest": "2015-09-19T14:45:51.635818575+02:00",
  "end": "2015-09-19T14:45:51.639325797+02:00",
  "duration": 989999944,
  "wait": 3507222,
  "requests": 100,
  "rate": 101.01010672380401,
  "throughput": 101.00012489812,
  "success": 1,
  "status_codes": {
    "200": 100
  },
  "errors": []
}
```

In the `buckets` field, each key is a nanosecond value representing the lower bound of a bucket.
The upper bound is implied by the next higher bucket.
Upper bounds are non-inclusive.
The highest bucket is the overflow bucket; it has no upper bound.
The values are counts of how many requests fell into that particular bucket.
If the `-buckets` parameter is not present, the `buckets` field is omitted.

#### `report -type=hist`

Computes and prints a text based histogram for the given buckets.
Each bucket upper bound is non-inclusive.

```console
cat results.bin | vegeta report -type='hist[0,2ms,4ms,6ms]'
Bucket         #     %       Histogram
[0,     2ms]   6007  32.65%  ########################
[2ms,   4ms]   5505  29.92%  ######################
[4ms,   6ms]   2117  11.51%  ########
[6ms,   +Inf]  4771  25.93%  ###################
```

#### `report -type=hdrplot`

Writes out results in a format plottable by https://hdrhistogram.github.io/HdrHistogram/plotFiles.html.

```
Value(ms)  Percentile  TotalCount  1/(1-Percentile)
0.076715   0.000000    0           1.000000
0.439370   0.100000    200         1.111111
0.480836   0.200000    400         1.250000
0.495559   0.300000    599         1.428571
0.505101   0.400000    799         1.666667
0.513059   0.500000    999         2.000000
0.516664   0.550000    1099        2.222222
0.520455   0.600000    1199        2.500000
0.525008   0.650000    1299        2.857143
0.530174   0.700000    1399        3.333333
0.534891   0.750000    1499        4.000000
0.537572   0.775000    1548        4.444444
0.540340   0.800000    1598        5.000000
0.543763   0.825000    1648        5.714286
0.547164   0.850000    1698        6.666667
0.551432   0.875000    1748        8.000000
0.553444   0.887500    1773        8.888889
0.555774   0.900000    1798        10.000000
0.558454   0.912500    1823        11.428571
0.562123   0.925000    1848        13.333333
0.565563   0.937500    1873        16.000000
0.567831   0.943750    1886        17.777778
0.570617   0.950000    1898        20.000000
0.574522   0.956250    1911        22.857143
0.579046   0.962500    1923        26.666667
0.584426   0.968750    1936        32.000000
0.586695   0.971875    1942        35.555556
0.590451   0.975000    1948        40.000000
0.597543   0.978125    1954        45.714286
0.605637   0.981250    1961        53.333333
0.613564   0.984375    1967        64.000000
0.620393   0.985938    1970        71.113640
0.629121   0.987500    1973        80.000000
0.638060   0.989062    1976        91.424392
0.648085   0.990625    1979        106.666667
0.659689   0.992188    1982        128.008193
0.665870   0.992969    1984        142.227279
0.672985   0.993750    1986        160.000000
0.680101   0.994531    1987        182.848784
0.687810   0.995313    1989        213.356091
0.695729   0.996094    1990        256.016385
0.730641   0.996484    1991        284.414107
0.785516   0.996875    1992        320.000000
0.840392   0.997266    1993        365.764448
1.009646   0.997656    1993        426.621160
1.347020   0.998047    1994        512.032770
1.515276   0.998242    1994        568.828214
1.683532   0.998437    1995        639.795266
1.887487   0.998633    1995        731.528895
2.106249   0.998828    1996        853.242321
2.325011   0.999023    1996        1023.541453
2.434952   0.999121    1996        1137.656428
2.544894   0.999219    1996        1280.409731
2.589510   0.999316    1997        1461.988304
2.605192   0.999414    1997        1706.484642
2.620873   0.999512    1997        2049.180328
2.628713   0.999561    1997        2277.904328
2.636394   0.999609    1997        2557.544757
2.644234   0.999658    1997        2923.976608
2.652075   0.999707    1997        3412.969283
2.658916   0.999756    1998        4098.360656
2.658916   0.999780    1998        4545.454545
2.658916   0.999805    1998        5128.205128
2.658916   0.999829    1998        5847.953216
2.658916   0.999854    1998        6849.315068
2.658916   0.999878    1998        8196.721311
2.658916   0.999890    1998        9090.909091
2.658916   0.999902    1998        10204.081633
2.658916   0.999915    1998        11764.705882
2.658916   0.999927    1998        13698.630137
2.658916   0.999939    1998        16393.442623
2.658916   0.999945    1998        18181.818182
2.658916   0.999951    1998        20408.163265
2.658916   0.999957    1998        23255.813953
2.658916   0.999963    1998        27027.027027
2.658916   0.999969    1998        32258.064516
2.658916   0.999973    1998        37037.037037
2.658916   0.999976    1998        41666.666667
2.658916   0.999979    1998        47619.047619
2.658916   0.999982    1998        55555.555556
2.658916   0.999985    1998        66666.666667
2.658916   0.999986    1998        71428.571429
2.658916   0.999988    1998        83333.333333
2.658916   0.999989    1998        90909.090909
2.658916   0.999991    1998        111111.111111
2.658916   0.999992    1998        125000.000000
2.658916   0.999993    1998        142857.142858
2.658916   0.999994    1998        166666.666668
2.658916   0.999995    1998        199999.999999
2.658916   0.999996    1998        250000.000000
2.658916   0.999997    1998        333333.333336
2.658916   0.999998    1998        500000.000013
2.658916   0.999999    1998        999999.999971
2.658916   1.000000    1998        10000000.000000
```

### `encode` command

```
Usage: vegeta encode [options] [<file>...]

Encodes vegeta attack results from one encoding to another.
The supported encodings are Gob (binary), CSV and JSON.
Each input file may have a different encoding which is detected
automatically.

The CSV encoder doesn't write a header. The columns written by it are:

  1. Unix timestamp in nanoseconds since epoch
  2. HTTP status code
  3. Request latency in nanoseconds
  4. Bytes out
  5. Bytes in
  6. Error
  7. Base64 encoded response body
  8. Attack name
  9. Sequence number of request
  10. Method
  11. URL
  12. Base64 encoded response headers

Arguments:
  <file>  A file with vegeta attack results encoded with one of
          the supported encodings (gob | json | csv) [default: stdin]

Options:
  --to      Output encoding (gob | json | csv) [default: json]
  --output  Output file [default: stdout]

Examples:
  echo "GET http://:80" | vegeta attack -rate=1/s > results.gob
  cat results.gob | vegeta encode | jq -c 'del(.body)' | vegeta encode -to gob
```

### `plot` command

![Plot](https://i.imgur.com/Jra1sNH.png)

```
Usage: vegeta plot [options] [<file>...]

Outputs an HTML time series plot of request latencies over time.
The X axis represents elapsed time in seconds from the beginning
of the earliest attack in all input files. The Y axis represents
request latency in milliseconds.

Click and drag to select a region to zoom into. Double click to zoom out.
Choose a different number on the bottom left corner input field
to change the moving average window size (in data points).

Arguments:
  <file>  A file output by running vegeta attack [default: stdin]

Options:
  --title      Title and header of the resulting HTML page.
               [default: Vegeta Plot]
  --threshold  Threshold of data points to downsample series to.
               Series with less than --threshold number of data
               points are not downsampled. [default: 4000]

Examples:
  echo "GET http://:80" | vegeta attack -name=50qps -rate=50 -duration=5s > results.50qps.bin
  cat results.50qps.bin | vegeta plot > plot.50qps.html
  echo "GET http://:80" | vegeta attack -name=100qps -rate=100 -duration=5s > results.100qps.bin
  vegeta plot results.50qps.bin results.100qps.bin > plot.html
```

## Usage: Generated targets

Apart from accepting a static list of targets, Vegeta can be used together with another program that generates them in a streaming fashion. Here's an example of that using the `jq` utility that generates targets with an incrementing id in their body.

```console
jq -ncM 'while(true; .+1) | {method: "POST", url: "http://:6060", body: {id: .} | @base64 }' | \
  vegeta attack -rate=50/s -lazy -format=json -duration=30s | \
  tee results.bin | \
  vegeta report
```

## Usage: Distributed attacks

Whenever your load test can't be conducted due to Vegeta hitting machine limits
such as open files, memory, CPU or network bandwidth, it's a good idea to use Vegeta in a distributed manner.

In a hypothetical scenario where the desired attack rate is 60k requests per second,
let's assume we have 3 machines with `vegeta` installed.

Make sure open file descriptor and process limits are set to a high number for your user **on each machine**
using the `ulimit` command.

We're ready to start the attack. All we need to do is to divide the intended rate by the number of machines,
and use that number on each attack. Here we'll use [pdsh](https://code.google.com/p/pdsh/) for orchestration.

```shell
$ PDSH_RCMD_TYPE=ssh pdsh -b -w '10.0.1.1,10.0.2.1,10.0.3.1' \
    'echo "GET http://target/" | vegeta attack -rate=20000 -duration=60s > result.bin'
```

After the previous command finishes, we can gather the result files to use on our report.

```shell
$ for machine in 10.0.1.1 10.0.2.1 10.0.3.1; do
    scp $machine:~/result.bin $machine.bin &
  done
```

The `report` command accepts multiple result files.
It'll read and sort them by timestamp before generating reports.

```console
vegeta report *.bin
```

Another way to gather results in distributed tests is to use the built-in Prometheus Exporter and configure a Prometheus Server to get test results from all Vegeta instances. See `attack` option "prometheus-addr" for more details and a complete example in the section "Prometheus Support".

## Usage: Real-time Analysis

If you are a happy user of iTerm, you can integrate vegeta with [jplot](https://github.com/rs/jplot) using [jaggr](https://github.com/rs/jaggr) to plot a vegeta report in real-time in the comfort of your terminal:

```
echo 'GET http://localhost:8080' | \
    vegeta attack -rate 5000 -duration 10m | vegeta encode | \
    jaggr @count=rps \
          hist\[100,200,300,400,500\]:code \
          p25,p50,p95:latency \
          sum:bytes_in \
          sum:bytes_out | \
    jplot rps+code.hist.100+code.hist.200+code.hist.300+code.hist.400+code.hist.500 \
          latency.p95+latency.p50+latency.p25 \
          bytes_in.sum+bytes_out.sum
```

![](https://i.imgur.com/ttBDsQS.gif)

## Usage: Library

The library versioning follows [SemVer v2.0.0](https://semver.org/spec/v2.0.0.html).
Since [lib/v9.0.0](https://github.com/tsenart/vegeta/tree/lib/v9.0.0), the library and cli
are versioned separately to better isolate breaking changes to each component.

See [Versioning](#Versioning) for more details on git tag naming schemes and compatibility
with `go mod`.

```go
package main

import (
  "fmt"
  "time"

  vegeta "github.com/tsenart/vegeta/v12/lib"
)

func main() {
  rate := vegeta.Rate{Freq: 100, Per: time.Second}
  duration := 4 * time.Second
  targeter := vegeta.NewStaticTargeter(vegeta.Target{
    Method: "GET",
    URL:    "http://localhost:9100/",
  })
  attacker := vegeta.NewAttacker()

  var metrics vegeta.Metrics
  for res := range attacker.Attack(targeter, rate, duration, "Big Bang!") {
    metrics.Add(res)
  }
  metrics.Close()

  fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
}
```

#### Limitations

There will be an upper bound of the supported `rate` which varies on the
machine being used.
You could be CPU bound (unlikely), memory bound (more likely) or
have system resource limits being reached which ought to be tuned for
the process execution. The important limits for us are file descriptors
and processes. On a UNIX system you can get and set the current
soft-limit values for a user.

```shell
$ ulimit -n # file descriptors
2560
$ ulimit -u # processes / threads
709
```

Just pass a new number as the argument to change it.

## Prometheus support

Vegeta has a built-in Prometheus Exporter that may be enabled during attacks so that you can point any Prometheus instance to Vegeta attack processes and monitor attack metrics.

To enable the Prometheus Exporter on the command line, set the "prometheus-addr" flag.

A Prometheus HTTP endpoint will be available only during the lifespan of an attack and will be closed right after the attack is finished.

The following metrics are exposed:

* `request_bytes_in` - bytes count received from targeted servers by "url", "method" and "status"
* `request_bytes_out` - bytes count sent to targeted server by "url", "method" and "status"
* `request_seconds` - histogram with request latency and counters by "url", "method" and "status"
* `request_fail_count` - count of failed requests by "url", "method", "status" and "message"

<image src="lib/prom/prometheus-sample.png" width="500" />

Check file [lib/prom/grafana.json](lib/prom/grafana.json) with the source of this sample dashboard in Grafana.

### Limitations

1. Prometheus scrapes metrics from a running vegeta attack process and assigns timestamps to samples on its server. This means result timestamps aren't accurate (i.e. they're scraping time, not result time).
2. Configuring Prometheus to scrape vegeta needs to happen out-of-band. That's a hassle!
3. Since there's no coordination between a vegeta attack process and a Prometheus server, an attack process will finish before Prometheus has the chance to scrape the latest observations.


Why aren't we using pushgateway instead? See [this comment](https://github.com/tsenart/vegeta/pull/534#issuecomment-1629943731).

There's [an issue](https://github.com/tsenart/vegeta/issues/637) tracking the proper solution to all these limitations which is a remote write integration.

## License

See [LICENSE](LICENSE).

## Donate

If you use and love Vegeta, please consider sending some Satoshi to
`1MDmKC51ve7Upxt75KoNM6x1qdXHFK6iW2`. In case you want to be mentioned as a
sponsor, let me know!

[![Donate Bitcoin](https://i.imgur.com/W9Vc51d.png)](#donate)


================================================
FILE: attack.go
================================================
package main

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/tsenart/vegeta/v12/internal/resolver"
	vegeta "github.com/tsenart/vegeta/v12/lib"
	prom "github.com/tsenart/vegeta/v12/lib/prom"
)

func attackCmd() command {
	fs := flag.NewFlagSet("vegeta attack", flag.ExitOnError)
	opts := &attackOpts{
		headers:      headers{http.Header{}},
		proxyHeaders: headers{http.Header{}},
		laddr:        localAddr{&vegeta.DefaultLocalAddr},
		rate:         vegeta.Rate{Freq: 50, Per: time.Second},
		maxBody:      vegeta.DefaultMaxBody,
		promAddr:     "0.0.0.0:8880",
	}
	fs.StringVar(&opts.name, "name", "", "Attack name")
	fs.StringVar(&opts.targetsf, "targets", "stdin", "Targets file")
	fs.StringVar(&opts.format, "format", vegeta.HTTPTargetFormat,
		fmt.Sprintf("Targets format [%s]", strings.Join(vegeta.TargetFormats, ", ")))
	fs.StringVar(&opts.outputf, "output", "stdout", "Output file")
	fs.StringVar(&opts.bodyf, "body", "", "Requests body file")
	fs.BoolVar(&opts.chunked, "chunked", false, "Send body with chunked transfer encoding")
	fs.StringVar(&opts.certf, "cert", "", "TLS client PEM encoded certificate file")
	fs.StringVar(&opts.keyf, "key", "", "TLS client PEM encoded private key file")
	fs.Var(&opts.rootCerts, "root-certs", "TLS root certificate files (comma separated list)")
	fs.BoolVar(&opts.http2, "http2", true, "Send HTTP/2 requests when supported by the server")
	fs.BoolVar(&opts.h2c, "h2c", false, "Send HTTP/2 requests without TLS encryption")
	fs.BoolVar(&opts.insecure, "insecure", false, "Ignore invalid server TLS certificates")
	fs.BoolVar(&opts.lazy, "lazy", false, "Read targets lazily")
	fs.DurationVar(&opts.duration, "duration", 0, "Duration of the test [0 = forever]")
	fs.DurationVar(&opts.timeout, "timeout", vegeta.DefaultTimeout, "Requests timeout")
	fs.Uint64Var(&opts.workers, "workers", vegeta.DefaultWorkers, "Initial number of workers")
	fs.Uint64Var(&opts.maxWorkers, "max-workers", vegeta.DefaultMaxWorkers, "Maximum number of workers")
	fs.IntVar(&opts.connections, "connections", vegeta.DefaultConnections, "Max open idle connections per target host")
	fs.IntVar(&opts.maxConnections, "max-connections", vegeta.DefaultMaxConnections, "Max connections per target host")
	fs.IntVar(&opts.redirects, "redirects", vegeta.DefaultRedirects, "Number of redirects to follow. -1 will not follow but marks as success")
	fs.Var(&maxBodyFlag{&opts.maxBody}, "max-body", "Maximum number of bytes to capture from response bodies. [-1 = no limit]")
	fs.Var(&rateFlag{&opts.rate}, "rate", "Number of requests per time unit [0 = infinity]")
	fs.Var(&opts.headers, "header", "Request header")
	fs.Var(&opts.proxyHeaders, "proxy-header", "Proxy CONNECT header")
	fs.Var(&opts.laddr, "laddr", "Local IP address")
	fs.BoolVar(&opts.keepalive, "keepalive", true, "Use persistent connections")
	fs.StringVar(&opts.unixSocket, "unix-socket", "", "Connect over a unix socket. This overrides the host address in target URLs")
	fs.StringVar(&opts.promAddr, "prometheus-addr", "", "Prometheus exporter listen address [empty = disabled]. Example: 0.0.0.0:8880")
	fs.Var(&dnsTTLFlag{&opts.dnsTTL}, "dns-ttl", "Cache DNS lookups for the given duration [-1 = disabled, 0 = forever]")
	fs.BoolVar(&opts.sessionTickets, "session-tickets", false, "Enable TLS session resumption using session tickets")
	fs.Var(&connectToFlag{&opts.connectTo}, "connect-to", "A mapping of (ip|host):port to use instead of a target URL's (ip|host):port. Can be repeated multiple times.\nIdentical src:port with different dst:port will round-robin over the different dst:port pairs.\nExample: google.com:80:localhost:6060")
	systemSpecificFlags(fs, opts)

	return command{fs, func(args []string) error {
		fs.Parse(args)
		return attack(opts)
	}}
}

var (
	errZeroRate = errors.New("rate frequency and time unit must be bigger than zero")
	errBadCert  = errors.New("bad certificate")
)

// attackOpts aggregates the attack function command options
type attackOpts struct {
	name           string
	targetsf       string
	format         string
	outputf        string
	bodyf          string
	certf          string
	keyf           string
	rootCerts      csl
	http2          bool
	h2c            bool
	insecure       bool
	lazy           bool
	chunked        bool
	duration       time.Duration
	timeout        time.Duration
	rate           vegeta.Rate
	workers        uint64
	maxWorkers     uint64
	connections    int
	maxConnections int
	redirects      int
	maxBody        int64
	headers        headers
	proxyHeaders   headers
	laddr          localAddr
	keepalive      bool
	resolvers      csl
	unixSocket     string
	promAddr       string
	dnsTTL         time.Duration
	sessionTickets bool
	connectTo      map[string][]string
}

// attack validates the attack arguments, sets up the
// required resources, launches the attack and writes the results
func attack(opts *attackOpts) (err error) {
	if opts.maxWorkers == vegeta.DefaultMaxWorkers && opts.rate.Freq == 0 {
		return fmt.Errorf("-rate=0 requires setting -max-workers")
	}

	if len(opts.resolvers) > 0 {
		res, err := resolver.NewResolver(opts.resolvers)
		if err != nil {
			return err
		}
		net.DefaultResolver = res
	}

	net.DefaultResolver.PreferGo = true

	files := map[string]io.Reader{}
	for _, filename := range []string{opts.targetsf, opts.bodyf} {
		if filename == "" {
			continue
		}
		f, err := file(filename, false)
		if err != nil {
			return fmt.Errorf("error opening %s: %s", filename, err)
		}
		defer f.Close()
		files[filename] = f
	}

	var body []byte
	if bodyf, ok := files[opts.bodyf]; ok {
		if body, err = io.ReadAll(bodyf); err != nil {
			return fmt.Errorf("error reading %s: %s", opts.bodyf, err)
		}
	}

	var (
		tr       vegeta.Targeter
		src      = files[opts.targetsf]
		hdr      = opts.headers.Header
		proxyHdr = opts.proxyHeaders.Header
	)

	switch opts.format {
	case vegeta.JSONTargetFormat:
		tr = vegeta.NewJSONTargeter(src, body, hdr)
	case vegeta.HTTPTargetFormat:
		tr = vegeta.NewHTTPTargeter(src, body, hdr)
	default:
		return fmt.Errorf("format %q isn't one of [%s]",
			opts.format, strings.Join(vegeta.TargetFormats, ", "))
	}

	if !opts.lazy {
		targets, err := vegeta.ReadAllTargets(tr)
		if err != nil {
			return err
		}
		tr = vegeta.NewStaticTargeter(targets...)
	}

	out, err := file(opts.outputf, true)
	if err != nil {
		return fmt.Errorf("error opening %s: %s", opts.outputf, err)
	}
	defer out.Close()

	tlsc, err := tlsConfig(opts.insecure, opts.certf, opts.keyf, opts.rootCerts)
	if err != nil {
		return err
	}

	var pm *prom.Metrics
	if opts.promAddr != "" {
		pm = prom.NewMetrics()

		r := prometheus.NewRegistry()
		if err := pm.Register(r); err != nil {
			return fmt.Errorf("error registering prometheus metrics: %s", err)
		}

		srv := http.Server{
			Addr:    opts.promAddr,
			Handler: prom.NewHandler(r, time.Now().UTC()),
		}

		defer srv.Close()
		go srv.ListenAndServe()
	}

	atk := vegeta.NewAttacker(
		vegeta.Redirects(opts.redirects),
		vegeta.Timeout(opts.timeout),
		vegeta.LocalAddr(*opts.laddr.IPAddr),
		vegeta.TLSConfig(tlsc),
		vegeta.Workers(opts.workers),
		vegeta.MaxWorkers(opts.maxWorkers),
		vegeta.KeepAlive(opts.keepalive),
		vegeta.Connections(opts.connections),
		vegeta.MaxConnections(opts.maxConnections),
		vegeta.HTTP2(opts.http2),
		vegeta.H2C(opts.h2c),
		vegeta.MaxBody(opts.maxBody),
		vegeta.UnixSocket(opts.unixSocket),
		vegeta.ProxyHeader(proxyHdr),
		vegeta.ChunkedBody(opts.chunked),
		vegeta.DNSCaching(opts.dnsTTL),
		vegeta.ConnectTo(opts.connectTo),
		vegeta.SessionTickets(opts.sessionTickets),
	)

	res := atk.Attack(tr, opts.rate, opts.duration, opts.name)
	enc := vegeta.NewEncoder(out)
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, os.Interrupt, syscall.SIGTERM)

	return processAttack(atk, res, enc, sig, pm)
}

func processAttack(
	atk *vegeta.Attacker,
	res <-chan *vegeta.Result,
	enc vegeta.Encoder,
	sig <-chan os.Signal,
	pm *prom.Metrics,
) error {
	for {
		select {
		case <-sig:
			if stopSent := atk.Stop(); !stopSent {
				// Exit immediately on second signal.
				return nil
			}
		case r, ok := <-res:
			if !ok {
				return nil
			}

			if pm != nil {
				pm.Observe(r)
			}

			if err := enc.Encode(r); err != nil {
				return err
			}
		}
	}
}

// tlsConfig builds a *tls.Config from the given options.
func tlsConfig(insecure bool, certf, keyf string, rootCerts []string) (*tls.Config, error) {
	var err error
	files := map[string][]byte{}
	filenames := append([]string{certf, keyf}, rootCerts...)
	for _, f := range filenames {
		if f != "" {
			if files[f], err = os.ReadFile(f); err != nil {
				return nil, err
			}
		}
	}

	c := tls.Config{InsecureSkipVerify: insecure}
	if cert, ok := files[certf]; ok {
		key, ok := files[keyf]
		if !ok {
			key = cert
		}

		certificate, err := tls.X509KeyPair(cert, key)
		if err != nil {
			return nil, err
		}

		c.Certificates = append(c.Certificates, certificate)
		c.BuildNameToCertificate()
	}

	if len(rootCerts) > 0 {
		c.RootCAs = x509.NewCertPool()
		for _, f := range rootCerts {
			if !c.RootCAs.AppendCertsFromPEM(files[f]) {
				return nil, errBadCert
			}
		}
	}

	return &c, nil
}


================================================
FILE: attack_nonwindows.go
================================================
//go:build !windows
// +build !windows

package main

import "flag"

func systemSpecificFlags(fs *flag.FlagSet, opts *attackOpts) {
	fs.Var(&opts.resolvers, "resolvers", "List of addresses (ip:port) to use for DNS resolution. Disables use of local system DNS. (comma separated list)")
}


================================================
FILE: attack_test.go
================================================
package main

import (
	"bufio"
	"bytes"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"reflect"
	"sync"
	"testing"
	"time"

	vegeta "github.com/tsenart/vegeta/v12/lib"
)

func TestHeadersSet(t *testing.T) {
	h := headers{
		Header: make(http.Header),
	}
	for i, tt := range []struct {
		key, val string
		want     []string
	}{
		{"key", "value", []string{"value"}},
		{"key", "value", []string{"value", "value"}},
		{"Key", "Value", []string{"Value"}},
		{"KEY", "VALUE", []string{"VALUE"}},
	} {
		if err := h.Set(tt.key + ": " + tt.val); err != nil {
			t.Error(err)
		} else if got := h.Header[tt.key]; !reflect.DeepEqual(got, tt.want) {
			t.Errorf("test #%d, '%s: %s': got: %+v, want: %+v", i, tt.key, tt.val, got, tt.want)
		}
	}
}

func decodeMetrics(buf bytes.Buffer) (vegeta.Metrics, error) {
	var metrics vegeta.Metrics
	dec := vegeta.NewDecoder(bufio.NewReader(&buf))

	for {
		var r vegeta.Result
		if err := dec.Decode(&r); err != nil {
			if err == io.EOF {
				break
			}
			return metrics, err
		}
		metrics.Add(&r)
	}
	metrics.Close()

	return metrics, nil
}

func TestAttackSignalOnce(t *testing.T) {
	t.Parallel()

	const (
		signalDelay    = 300 * time.Millisecond // Delay before stopping.
		clientTimeout  = 1 * time.Second        // This, plus delay, is the max time for the attack.
		serverTimeout  = 2 * time.Second        // Must be more than clientTimeout.
		attackDuration = 10 * time.Second       // The attack should never take this long.
	)

	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			time.Sleep(serverTimeout) // Server.Close() will block for this long on shutdown.
		}),
	)
	defer server.Close()

	tr := vegeta.NewStaticTargeter(vegeta.Target{Method: "GET", URL: server.URL})
	atk := vegeta.NewAttacker(vegeta.Timeout(clientTimeout))
	rate := vegeta.Rate{Freq: 10, Per: time.Second} // Every 100ms.

	var buf bytes.Buffer
	writer := bufio.NewWriter(&buf)
	enc := vegeta.NewEncoder(writer)
	sig := make(chan os.Signal, 1)
	res := atk.Attack(tr, rate, attackDuration, "")

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		processAttack(atk, res, enc, sig, nil)
	}()

	// Allow more than one request to have started before stopping.
	time.Sleep(signalDelay)
	sig <- os.Interrupt
	wg.Wait()
	writer.Flush()

	metrics, err := decodeMetrics(buf)
	if err != nil {
		t.Error(err)
	}
	if got, min := metrics.Requests, uint64(2); got < min {
		t.Errorf("not enough requests recorded. got %+v, min: %+v", got, min)
	}
	if got, want := metrics.Success, 0.0; got != want {
		t.Errorf("all requests should fail. got %+v, want: %+v", got, want)
	}
	if got, max := metrics.Duration, clientTimeout; got > max {
		t.Errorf("attack duration too long. got %+v, max: %+v", got, max)
	}
	if got, want := metrics.Wait.Round(time.Second), clientTimeout; got != want {
		t.Errorf("attack wait doesn't match timeout. got %+v, want: %+v", got, want)
	}
}

func TestAttackSignalTwice(t *testing.T) {
	t.Parallel()

	const (
		attackDuration = 10 * time.Second // The attack should never take this long.
	)

	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
	)
	defer server.Close()

	tr := vegeta.NewStaticTargeter(vegeta.Target{Method: "GET", URL: server.URL})
	atk := vegeta.NewAttacker()
	rate := vegeta.Rate{Freq: 1, Per: time.Second}

	var buf bytes.Buffer
	writer := bufio.NewWriter(&buf)
	enc := vegeta.NewEncoder(writer)
	sig := make(chan os.Signal, 1)
	res := atk.Attack(tr, rate, attackDuration, "")

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		processAttack(atk, res, enc, sig, nil)
	}()

	// Exit as soon as possible.
	sig <- os.Interrupt
	sig <- os.Interrupt
	wg.Wait()
	writer.Flush()

	metrics, err := decodeMetrics(buf)
	if err != nil {
		t.Error(err)
	}
	if got, max := metrics.Duration, time.Second; got > max {
		t.Errorf("attack duration too long. got %+v, max: %+v", got, max)
	}
}


================================================
FILE: attack_windows.go
================================================
package main

import "flag"

func systemSpecificFlags(fs *flag.FlagSet, opts *attackOpts) {}


================================================
FILE: dump.go
================================================
package main

import (
	"fmt"
)

func dumpCmd() command {
	return command{fn: func([]string) error {
		return fmt.Errorf("vegeta dump has been deprecated and succeeded by the vegeta encode command")
	}}
}


================================================
FILE: encode.go
================================================
package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"

	vegeta "github.com/tsenart/vegeta/v12/lib"
)

const (
	encodingCSV  = "csv"
	encodingGob  = "gob"
	encodingJSON = "json"
)

const encodeUsage = `Usage: vegeta encode [options] [<file>...]

Encodes vegeta attack results from one encoding to another.
The supported encodings are Gob (binary), CSV and JSON.
Each input file may have a different encoding which is detected
automatically.

The CSV encoder doesn't write a header. The columns written by it are:

   1. Unix timestamp in nanoseconds since epoch
   2. HTTP status code
   3. Request latency in nanoseconds
   4. Bytes out
   5. Bytes in
   6. Error
   7. Base64 encoded response body
   8. Attack name
   9. Sequence number of request
  10. Method
  11. URL
  12. Base64 encoded response headers

Arguments:
  <file>  A file with vegeta attack results encoded with one of
          the supported encodings (gob | json | csv) [default: stdin]

Options:
  --to      Output encoding (gob | json | csv) [default: json]
  --output  Output file [default: stdout]

Examples:
  echo "GET http://:80" | vegeta attack -rate=1/s > results.gob
  cat results.gob | vegeta encode | jq -c 'del(.body)' | vegeta encode -to gob
`

func encodeCmd() command {
	encs := "[" + strings.Join([]string{encodingCSV, encodingGob, encodingJSON}, ", ") + "]"
	fs := flag.NewFlagSet("vegeta encode", flag.ExitOnError)
	to := fs.String("to", encodingJSON, "Output encoding "+encs)
	output := fs.String("output", "stdout", "Output file")

	fs.Usage = func() {
		fmt.Fprintf(os.Stderr, "%s\n", encodeUsage)
	}

	return command{fs, func(args []string) error {
		fs.Parse(args)
		files := fs.Args()
		if len(files) == 0 {
			files = append(files, "stdin")
		}
		return encode(files, *to, *output)
	}}
}

func encode(files []string, to, output string) error {
	dec, mc, err := decoder(files)
	defer mc.Close()
	if err != nil {
		return err
	}

	out, err := file(output, true)
	if err != nil {
		return err
	}
	defer out.Close()

	var enc vegeta.Encoder
	switch to {
	case encodingCSV:
		enc = vegeta.NewCSVEncoder(out)
	case encodingGob:
		enc = vegeta.NewEncoder(out)
	case encodingJSON:
		enc = vegeta.NewJSONEncoder(out)
	default:
		return fmt.Errorf("encode: unknown encoding %q", to)
	}

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, os.Interrupt)

	for {
		select {
		case <-sigch:
			return nil
		default:
		}

		var r vegeta.Result
		if err = dec.Decode(&r); err != nil {
			if err == io.EOF {
				break
			}
			return err
		} else if err = enc.Encode(&r); err != nil {
			return err
		}
	}

	return nil
}


================================================
FILE: file.go
================================================
package main

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	vegeta "github.com/tsenart/vegeta/v12/lib"
)

func file(name string, create bool) (*os.File, error) {
	switch name {
	case "stdin":
		return os.Stdin, nil
	case "stdout":
		return os.Stdout, nil
	default:
		if create {
			return os.Create(name)
		}
		return os.Open(name)
	}
}

func decoder(files []string) (vegeta.Decoder, io.Closer, error) {
	closer := make(multiCloser, 0, len(files))
	decs := make([]vegeta.Decoder, 0, len(files))
	for _, f := range files {
		rc, err := file(f, false)
		if err != nil {
			return nil, closer, err
		}

		dec := vegeta.DecoderFor(rc)
		if dec == nil {
			return nil, closer, fmt.Errorf("encode: can't detect encoding of %q", f)
		}

		decs = append(decs, dec)
		closer = append(closer, rc)
	}
	return vegeta.NewRoundRobinDecoder(decs...), closer, nil
}

type multiCloser []io.Closer

func (mc multiCloser) Close() error {
	var errs []string
	for _, c := range mc {
		if err := c.Close(); err != nil {
			errs = append(errs, err.Error())
		}
	}

	if len(errs) > 0 {
		return errors.New(strings.Join(errs, "; "))
	}

	return nil
}


================================================
FILE: flags.go
================================================
package main

import (
	"bytes"
	"fmt"
	"math"
	"net"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/c2h5oh/datasize"
	vegeta "github.com/tsenart/vegeta/v12/lib"
)

// headers is the http.Header used in each target request
// it is defined here to implement the flag.Value interface
// in order to support multiple identical flags for request header
// specification
type headers struct{ http.Header }

func (h headers) String() string {
	buf := &bytes.Buffer{}
	if err := h.Write(buf); err != nil {
		return ""
	}
	return buf.String()
}

// Set implements the flag.Value interface for a map of HTTP Headers.
func (h headers) Set(value string) error {
	parts := strings.SplitN(value, ":", 2)
	if len(parts) != 2 {
		return fmt.Errorf("header '%s' has a wrong format", value)
	}
	key, val := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
	if key == "" || val == "" {
		return fmt.Errorf("header '%s' has a wrong format", value)
	}
	// Add key/value directly to the http.Header (map[string][]string).
	// http.Header.Add() canonicalizes keys but vegeta is used
	// to test systems that require case-sensitive headers.
	h.Header[key] = append(h.Header[key], val)
	return nil
}

// localAddr implements the Flag interface for parsing net.IPAddr
type localAddr struct{ *net.IPAddr }

func (ip *localAddr) Set(value string) (err error) {
	ip.IPAddr, err = net.ResolveIPAddr("ip", value)
	return
}

// csl implements the flag.Value interface for comma separated lists
type csl []string

func (l *csl) Set(v string) error {
	*l = strings.Split(v, ",")
	return nil
}

func (l csl) String() string { return strings.Join(l, ",") }

type rateFlag struct{ *vegeta.Rate }

func (f *rateFlag) Set(v string) (err error) {
	if v == "infinity" {
		return nil
	}

	ps := strings.SplitN(v, "/", 2)
	switch len(ps) {
	case 1:
		ps = append(ps, "1s")
	case 0:
		return fmt.Errorf("-rate format %q doesn't match the \"freq/duration\" format (i.e. 50/1s)", v)
	}

	f.Freq, err = strconv.Atoi(ps[0])
	if err != nil {
		return err
	}

	if f.Freq == 0 {
		return nil
	}

	switch ps[1] {
	case "ns", "us", "µs", "ms", "s", "m", "h":
		ps[1] = "1" + ps[1]
	}

	f.Per, err = time.ParseDuration(ps[1])
	return err
}

func (f *rateFlag) String() string {
	if f.Rate == nil {
		return ""
	}
	return fmt.Sprintf("%d/%s", f.Freq, f.Per)
}

type maxBodyFlag struct{ n *int64 }

func (f *maxBodyFlag) Set(v string) (err error) {
	if v == "-1" {
		*(f.n) = -1
		return nil
	}

	var ds datasize.ByteSize
	if err = ds.UnmarshalText([]byte(v)); err != nil {
		return err
	}

	if ds > math.MaxInt64 {
		return fmt.Errorf("-max-body=%d overflows int64", ds)
	}

	*(f.n) = int64(ds)
	return nil
}

func (f *maxBodyFlag) String() string {
	if f.n == nil {
		return ""
	} else if *(f.n) == -1 {
		return "-1"
	}
	return datasize.ByteSize(*(f.n)).String()
}

type dnsTTLFlag struct{ ttl *time.Duration }

func (f *dnsTTLFlag) Set(v string) (err error) {
	if v == "-1" {
		*(f.ttl) = -1
		return nil
	}

	*(f.ttl), err = time.ParseDuration(v)
	return err
}

func (f *dnsTTLFlag) String() string {
	if f.ttl == nil {
		return ""
	} else if *(f.ttl) == -1 {
		return "-1"
	}
	return f.ttl.String()
}

const connectToFormat = "src:port:dst:port"

type connectToFlag struct {
	addrMap *map[string][]string
}

func (c *connectToFlag) String() string {
	if c.addrMap == nil {
		return ""
	}

	addrMappings := make([]string, 0, len(*c.addrMap))
	for k, v := range *c.addrMap {
		addrMappings = append(addrMappings, k+":"+strings.Join(v, ","))
	}

	sort.Strings(addrMappings)
	return strings.Join(addrMappings, ";")
}

func (c *connectToFlag) Set(s string) error {
	if c.addrMap == nil {
		return nil
	}

	if *c.addrMap == nil {
		*c.addrMap = make(map[string][]string)
	}

	parts := strings.Split(s, ":")
	if len(parts) != 4 {
		return fmt.Errorf("invalid -connect-to %q, expected format: %s", s, connectToFormat)
	}
	srcAddr := parts[0] + ":" + parts[1]
	dstAddr := parts[2] + ":" + parts[3]

	// Parse source address
	if _, _, err := net.SplitHostPort(srcAddr); err != nil {
		return fmt.Errorf("invalid source address expression [%s], expected address:port", srcAddr)
	}

	// Parse destination address
	if _, _, err := net.SplitHostPort(dstAddr); err != nil {
		return fmt.Errorf("invalid destination address expression [%s], expected address:port", dstAddr)
	}

	(*c.addrMap)[srcAddr] = append((*c.addrMap)[srcAddr], dstAddr)

	return nil
}


================================================
FILE: go.mod
================================================
module github.com/tsenart/vegeta/v12

go 1.22

require (
	github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b
	github.com/bmizerany/perks v0.0.0-20230307044200-03f9df79da1e
	github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500
	github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654
	github.com/dgryski/go-lttb v0.0.0-20230207170358-f8fc36cdbff1
	github.com/google/go-cmp v0.6.0
	github.com/influxdata/tdigest v0.0.1
	github.com/mailru/easyjson v0.7.7
	github.com/miekg/dns v1.1.61
	github.com/prometheus/client_golang v1.19.1
	github.com/prometheus/prometheus v0.53.1
	github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529
	github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d
	github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3
	golang.org/x/net v0.27.0
	pgregory.net/rapid v1.1.0
)

require (
	github.com/beorn7/perks v1.0.1 // indirect
	github.com/cespare/xxhash/v2 v2.3.0 // indirect
	github.com/gogo/protobuf v1.3.2 // indirect
	github.com/golang/protobuf v1.5.4 // indirect
	github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect
	github.com/iancoleman/orderedmap v0.3.0 // indirect
	github.com/josharian/intern v1.0.0 // indirect
	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
	github.com/pkg/errors v0.9.1 // indirect
	github.com/prometheus/client_model v0.6.1 // indirect
	github.com/prometheus/common v0.55.0 // indirect
	github.com/prometheus/procfs v0.15.1 // indirect
	golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
	golang.org/x/mod v0.19.0 // indirect
	golang.org/x/sync v0.7.0 // indirect
	golang.org/x/sys v0.22.0 // indirect
	golang.org/x/text v0.16.0 // indirect
	golang.org/x/tools v0.23.0 // indirect
	google.golang.org/protobuf v1.34.2 // indirect
)


================================================
FILE: go.sum
================================================
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog=
github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
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/bmizerany/perks v0.0.0-20230307044200-03f9df79da1e h1:mWOqoK5jV13ChKf/aF3plwQ96laasTJgZi4f1aSOu+M=
github.com/bmizerany/perks v0.0.0-20230307044200-03f9df79da1e/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY=
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500 h1:6lhrsTEnloDPXyeZBvSYvQf8u86jbKehZPVDDlkgDl4=
github.com/c2h5oh/datasize v0.0.0-20231215233829-aa82cc1e6500/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654 h1:XOPLOMn/zT4jIgxfxSsoXPxkrzz0FaCHwp33x5POJ+Q=
github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E=
github.com/dgryski/go-lttb v0.0.0-20230207170358-f8fc36cdbff1 h1:dxwR3CStJdJamsIoMPCmxuIfBAPTgmzvFax+MvFav3M=
github.com/dgryski/go-lttb v0.0.0-20230207170358-f8fc36cdbff1/go.mod h1:UwftcHUI/qTYvLAxrWmANuRckf8+08O3C3hwStvkhDU=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd h1:PpuIBO5P3e9hpqBD0O/HjhShYuM6XE0i/lbE6J94kww=
github.com/grafana/regexp v0.0.0-20221122212121-6b5c0a4cb7fd/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248=
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY=
github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y=
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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/prometheus v0.47.2 h1:jWcnuQHz1o1Wu3MZ6nMJDuTI0kU5yJp9pkxh8XEkNvI=
github.com/prometheus/prometheus v0.47.2/go.mod h1:J/bmOSjgH7lFxz2gZhrWEZs2i64vMS+HIuZfmYNhJ/M=
github.com/prometheus/prometheus v0.53.1 h1:B0xu4VuVTKYrIuBMn/4YSUoIPYxs956qsOfcS4rqCuA=
github.com/prometheus/prometheus v0.53.1/go.mod h1:RZDkzs+ShMBDkAPQkLEaLBXpjmDcjhNxU2drUVPgKUU=
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs=
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d h1:X4+kt6zM/OVO6gbJdAfJR60MGPsqCzbtXNnjoGqdfAs=
github.com/streadway/quantile v0.0.0-20220407130108-4246515d968d/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3 h1:pcQGQzTwCg//7FgVywqge1sW9Yf8VMsMdG58MI5kd8s=
github.com/tsenart/go-tsz v0.0.0-20180814235614-0bd30b3df1c3/go.mod h1:SWZznP1z5Ki7hDT2ioqiFKEse8K9tU2OUvaRI0NeGQo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 h1:MGwJjxBy0HJshjDNfLsYO8xppfqWlA5ZT9OhtUUhTNw=
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca h1:PupagGYwj8+I4ubCxcmcBRk3VlUWtTg5huQpZR9flmE=
gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=


================================================
FILE: internal/cmd/echosrv/main.go
================================================
package main

import (
	"bytes"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"flag"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"sync/atomic"
	"time"
)

func main() {
	dump := flag.Bool("dump", false, "Dump HTTP requests to stdout")
	sleep := flag.Duration("sleep", 0, "Time to sleep per request")
	work := flag.Int("work", 0, "Artificial work load iteration count")

	flag.Parse()

	count := uint64(0)
	go func(last time.Time) {
		ticks := time.Tick(time.Second)
		for range ticks {
			rate := float64(atomic.SwapUint64(&count, 0)) / time.Since(last).Seconds()
			last = time.Now()
			log.Printf("Rate: %.3f/s", rate)
		}
	}(time.Now())

	http.ListenAndServe(flag.Arg(0), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer atomic.AddUint64(&count, 1)

		time.Sleep(*sleep)

		if _, err := hash(*work); err != nil {
			log.Printf("Error: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		bs, _ := httputil.DumpRequest(r, true)

		out := io.Writer(w)
		if *dump {
			out = io.MultiWriter(w, os.Stdout)
		}

		_, _ = out.Write(bs)
	}))
}

func hash(n int) (string, error) {
	if n == 0 {
		return "", nil
	}

	var buf bytes.Buffer
	_, err := io.CopyN(&buf, rand.Reader, 1024*1024) // 1MB
	if err != nil {
		return "", err
	}

	data := buf.Bytes()
	for i := 0; i < n; i++ {
		hash := sha256.Sum256(data)
		data = hash[:]
	}

	return base64.URLEncoding.EncodeToString(data), nil
}


================================================
FILE: internal/cmd/jsonschema/main.go
================================================
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/alecthomas/jsonschema"

	vegeta "github.com/tsenart/vegeta/v12/lib"
)

func main() {
	types := map[string]interface{}{
		"Target": &vegeta.Target{},
	}

	valid := strings.Join(keys(types), ", ")

	fs := flag.NewFlagSet("jsonschema", flag.ContinueOnError)
	typ := fs.String("type", "", fmt.Sprintf("Vegeta type to generate a JSON schema for [%s]", valid))
	out := fs.String("output", "stdout", "Output file")

	if err := fs.Parse(os.Args[1:]); err != nil {
		die("%s", err)
	}

	t, ok := types[*typ]
	if !ok {
		die("invalid type %q not in [%s]", *typ, valid)
	}

	schema, err := json.MarshalIndent(jsonschema.Reflect(t), "", "  ")
	if err != nil {
		die("%s", err)
	}

	switch *out {
	case "stdout":
		_, err = os.Stdout.Write(schema)
	default:
		err = os.WriteFile(*out, schema, 0644)
	}

	if err != nil {
		die("%s", err)
	}
}

func die(s string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, s, args...)
	os.Exit(1)
}

func keys(types map[string]interface{}) (ks []string) {
	for k := range types {
		ks = append(ks, k)
	}
	return ks
}


================================================
FILE: internal/resolver/resolver.go
================================================
package resolver

import (
	"context"
	"errors"
	"fmt"
	"net"
	"strconv"
	"strings"
	"sync/atomic"
)

type resolver struct {
	addrs  []string
	dialer *net.Dialer
	idx    uint64
}

// NewResolver - create a new instance of a dns resolver for plugging
// into net.DefaultResolver.  Addresses should be a list of
// ip addrs and optional port numbers, separated by colon.
// For example: 1.2.3.4:53 and 1.2.3.4 are both valid.  In the absence
// of a port number, 53 will be used instead.
func NewResolver(addrs []string) (*net.Resolver, error) {
	if len(addrs) == 0 {
		return nil, errors.New("must specify at least resolver address")
	}
	cleanAddrs, err := normalizeAddrs(addrs)
	if err != nil {
		return nil, err
	}
	return &net.Resolver{
		PreferGo: true,
		Dial:     (&resolver{addrs: cleanAddrs, dialer: &net.Dialer{}}).dial,
	}, nil
}

func normalizeAddrs(addrs []string) ([]string, error) {
	normal := make([]string, len(addrs))
	for i, addr := range addrs {

		// if addr has no port, give it 53
		if !strings.Contains(addr, ":") {
			addr += ":53"
		}

		// validate addr is a valid host:port
		host, portstr, err := net.SplitHostPort(addr)
		if err != nil {
			return nil, err
		}

		// validate valid port.
		_, err = strconv.ParseUint(portstr, 10, 16)
		if err != nil {
			return nil, err
		}

		// make sure host is an ip.
		ip := net.ParseIP(host)
		if ip == nil {
			return nil, fmt.Errorf("host %s is not an IP address", host)
		}

		normal[i] = addr
	}
	return normal, nil
}

// ignore the third parameter, as this represents the dns server address that
// we are overriding.
func (r *resolver) dial(ctx context.Context, network, _ string) (net.Conn, error) {
	return r.dialer.DialContext(ctx, network, r.address())
}

func (r *resolver) address() string {
	return r.addrs[atomic.AddUint64(&r.idx, 1)%uint64(len(r.addrs))]
}


================================================
FILE: internal/resolver/resolver_test.go
================================================
package resolver

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"reflect"
	"strings"
	"testing"
	"time"

	"github.com/miekg/dns"
)

const (
	fakeDomain = "acme.notadomain"
)

func TestResolver(t *testing.T) {
	dns.HandleFunc(".", func(w dns.ResponseWriter, r *dns.Msg) {
		m := &dns.Msg{}
		m.SetReply(r)
		localIP := net.ParseIP("127.0.0.1")
		defer func() {
			err := w.WriteMsg(m)
			if err != nil {
				t.Logf("got error writing dns message: %s", err)
			}
		}()
		if len(r.Question) == 0 {
			m.RecursionAvailable = true
			m.SetRcode(r, dns.RcodeRefused)
			return
		}

		q := r.Question[0]

		if q.Name == fakeDomain+"." {
			m.Answer = []dns.RR{&dns.A{
				Hdr: dns.RR_Header{
					Name:   q.Name,
					Rrtype: dns.TypeA,
					Class:  dns.ClassINET,
					Ttl:    1,
				},
				A: localIP,
			}}
		} else {
			m.SetRcode(r, dns.RcodeNameError)
		}
	})
	const payload = "there is no cloud, just someone else's computer"

	done := make(chan struct{})

	ds := dns.Server{
		Addr:              "127.0.0.1:0",
		Net:               "udp",
		UDPSize:           dns.MinMsgSize,
		ReadTimeout:       2 * time.Second,
		WriteTimeout:      2 * time.Second,
		NotifyStartedFunc: func() { close(done) },
	}

	go func() {
		err := ds.ListenAndServe()
		if err != nil {
			t.Logf("got error during dns ListenAndServe: %s", err)
		}
	}()

	defer func() {
		_ = ds.Shutdown()
	}()

	// wait for notify function to be called, ensuring ds.PacketConn is not nil.
	<-done

	res, err := NewResolver([]string{ds.PacketConn.LocalAddr().String()})
	if err != nil {
		t.Fatalf("error from NewResolver: %s", err)
	}
	net.DefaultResolver = res

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, payload)
	}))
	defer ts.Close()

	tsurl, _ := url.Parse(ts.URL)

	_, hport, err := net.SplitHostPort(tsurl.Host)
	if err != nil {
		t.Fatalf("could not parse port from httptest url %s: %s", ts.URL, err)
	}
	tsurl.Host = net.JoinHostPort(fakeDomain, hport)
	resp, err := http.Get(tsurl.String())
	if err != nil {
		t.Fatalf("failed resolver round trip: %s", err)
	}
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("failed to read respose body")
	}
	if strings.TrimSpace(string(body)) != payload {
		t.Errorf("body mismatch, got: '%s', expected: '%s'", body, payload)
	}
}

func TestNormalizeAddrs(t *testing.T) {
	for _, tc := range []struct {
		name string
		in   []string
		out  []string
		err  error
	}{
		{
			name: "default port 53",
			in:   []string{"127.0.0.1"},
			out:  []string{"127.0.0.1:53"},
		},
		{
			name: "invalid host port",
			in:   []string{"127.0.0.1.boom:53"},
			err:  errors.New("host 127.0.0.1.boom is not an IP address"),
		},
		{
			name: "invalid port",
			in:   []string{"127.0.0.1:999999999"},
			err:  errors.New(`strconv.ParseUint: parsing "999999999": value out of range`),
		},
		{
			name: "invalid IP",
			in:   []string{"127.0.0.500:53"},
			err:  errors.New(`host 127.0.0.500 is not an IP address`),
		},
		{
			name: "normalized",
			in:   []string{"127.0.0.1", "8.8.8.8:9000", "1.1.1.1"},
			out:  []string{"127.0.0.1:53", "8.8.8.8:9000", "1.1.1.1:53"},
		},
	} {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			addrs, err := normalizeAddrs(tc.in)
			if have, want := addrs, tc.out; !reflect.DeepEqual(have, want) {
				t.Errorf("have addrs: %v, want: %v", have, want)
			}

			if have, want := fmt.Sprint(err), fmt.Sprint(tc.err); have != want {
				t.Errorf("have err: %v, want: %v", have, want)
			}
		})
	}

}


================================================
FILE: lib/attack.go
================================================
package vegeta

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"math"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"sync"
	"time"

	"github.com/rs/dnscache"
	"golang.org/x/net/http2"
)

// Attacker is an attack executor which wraps an http.Client
type Attacker struct {
	dialer     *net.Dialer
	client     http.Client
	stopch     chan struct{}
	stopOnce   sync.Once
	workers    uint64
	maxWorkers uint64
	maxBody    int64
	redirects  int
	seqmu      sync.Mutex
	seq        uint64
	began      time.Time
	chunked    bool
}

const (
	// DefaultRedirects is the default number of times an Attacker follows
	// redirects.
	DefaultRedirects = 10
	// DefaultTimeout is the default amount of time an Attacker waits for a request
	// before it times out.
	DefaultTimeout = 30 * time.Second
	// DefaultConnections is the default amount of max open idle connections per
	// target host.
	DefaultConnections = 10000
	// DefaultMaxConnections is the default amount of connections per target
	// host.
	DefaultMaxConnections = 0
	// DefaultWorkers is the default initial number of workers used to carry an attack.
	DefaultWorkers = 10
	// DefaultMaxWorkers is the default maximum number of workers used to carry an attack.
	DefaultMaxWorkers = math.MaxUint64
	// DefaultMaxBody is the default max number of bytes to be read from response bodies.
	// Defaults to no limit.
	DefaultMaxBody = int64(-1)
	// NoFollow is the value when redirects are not followed but marked successful
	NoFollow = -1
)

var (
	// DefaultLocalAddr is the default local IP address an Attacker uses.
	DefaultLocalAddr = net.IPAddr{IP: net.IPv4zero}
	// DefaultTLSConfig is the default tls.Config an Attacker uses.
	DefaultTLSConfig = &tls.Config{InsecureSkipVerify: false}
)

// NewAttacker returns a new Attacker with default options which are overridden
// by the optionally provided opts.
func NewAttacker(opts ...func(*Attacker)) *Attacker {
	a := &Attacker{
		stopch:     make(chan struct{}),
		stopOnce:   sync.Once{},
		workers:    DefaultWorkers,
		maxWorkers: DefaultMaxWorkers,
		maxBody:    DefaultMaxBody,
	}

	a.dialer = &net.Dialer{
		LocalAddr: &net.TCPAddr{IP: DefaultLocalAddr.IP, Zone: DefaultLocalAddr.Zone},
		KeepAlive: 30 * time.Second,
	}

	a.client = http.Client{
		Timeout: DefaultTimeout,
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			DialContext:         a.dialer.DialContext,
			TLSClientConfig:     DefaultTLSConfig,
			MaxIdleConnsPerHost: DefaultConnections,
			MaxConnsPerHost:     DefaultMaxConnections,
		},
	}

	for _, opt := range opts {
		opt(a)
	}

	return a
}

// Workers returns a functional option which sets the initial number of workers
// an Attacker uses to hit its targets. More workers may be spawned dynamically
// to sustain the requested rate in the face of slow responses and errors.
func Workers(n uint64) func(*Attacker) {
	return func(a *Attacker) { a.workers = n }
}

// MaxWorkers returns a functional option which sets the maximum number of workers
// an Attacker can use to hit its targets.
func MaxWorkers(n uint64) func(*Attacker) {
	return func(a *Attacker) { a.maxWorkers = n }
}

// Connections returns a functional option which sets the number of maximum idle
// open connections per target host.
func Connections(n int) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.MaxIdleConnsPerHost = n
	}
}

// MaxConnections returns a functional option which sets the number of maximum
// connections per target host.
func MaxConnections(n int) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.MaxConnsPerHost = n
	}
}

// ChunkedBody returns a functional option which makes the attacker send the
// body of each request with the chunked transfer encoding.
func ChunkedBody(b bool) func(*Attacker) {
	return func(a *Attacker) { a.chunked = b }
}

// Redirects returns a functional option which sets the maximum
// number of redirects an Attacker will follow.
func Redirects(n int) func(*Attacker) {
	return func(a *Attacker) {
		a.redirects = n
		a.client.CheckRedirect = func(_ *http.Request, via []*http.Request) error {
			switch {
			case n == NoFollow:
				return http.ErrUseLastResponse
			case n < len(via):
				return fmt.Errorf("stopped after %d redirects", n)
			default:
				return nil
			}
		}
	}
}

// Proxy returns a functional option which sets the `Proxy` field on
// the http.Client's Transport
func Proxy(proxy func(*http.Request) (*url.URL, error)) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.Proxy = proxy
	}
}

// Timeout returns a functional option which sets the maximum amount of time
// an Attacker will wait for a request to be responded to and completely read.
func Timeout(d time.Duration) func(*Attacker) {
	return func(a *Attacker) {
		a.client.Timeout = d
	}
}

// LocalAddr returns a functional option which sets the local address
// an Attacker will use with its requests.
func LocalAddr(addr net.IPAddr) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		a.dialer.LocalAddr = &net.TCPAddr{IP: addr.IP, Zone: addr.Zone}
		tr.DialContext = a.dialer.DialContext
	}
}

// KeepAlive returns a functional option which toggles KeepAlive
// connections on the dialer and transport.
func KeepAlive(keepalive bool) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.DisableKeepAlives = !keepalive
		if !keepalive {
			a.dialer.KeepAlive = 0
			tr.DialContext = a.dialer.DialContext
		}
	}
}

// TLSConfig returns a functional option which sets the *tls.Config for a
// Attacker to use with its requests.
func TLSConfig(c *tls.Config) func(*Attacker) {
	return func(a *Attacker) {
		tr := a.client.Transport.(*http.Transport)
		tr.TLSClientConfig = c
	}
}

// HTTP2 returns a functional option which enables or disables HTTP/2 support
// on requests performed by an Attacker.
func HTTP2(enabled bool) func(*Attacker) {
	return func(a *Attacker) {
		if tr := a.client.Transport.(*http.Transport); enabled {
			http2.ConfigureTransport(tr)
		} else {
			tr.ForceAttemptHTTP2 = false
			tr.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{}
		}
	}
}

// H2C returns a functional option which enables H2C support on requests
// performed by an Attacker
func H2C(enabled bool) func(*Attacker) {
	return func(a *Attacker) {
		if tr := a.client.Transport.(*http.Transport); enabled {
			a.client.Transport = &http2.Transport{
				AllowHTTP: true,
				DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
					return tr.DialContext(ctx, network, addr)
				},
			}
		}
	}
}

// MaxBody returns a functional option which limits the max number of bytes
// read from response bodies. Set to -1 to disable any limits.
func MaxBody(n int64) func(*Attacker) {
	return func(a *Attacker) { a.maxBody = n }
}

// UnixSocket changes the dialer for the attacker to use the specified unix socket file
func UnixSocket(socket string) func(*Attacker) {
	return func(a *Attacker) {
		if tr, ok := a.client.Transport.(*http.Transport); socket != "" && ok {
			tr.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
				return net.Dial("unix", socket)
			}
		}
	}
}

// SessionTickets returns a functional option which configures usage of session
// tickets for TLS session resumption.
func SessionTickets(enabled bool) func(*Attacker) {
	return func(a *Attacker) {
		if enabled {
			cf := a.client.Transport.(*http.Transport).TLSClientConfig
			cf.SessionTicketsDisabled = false
			cf.ClientSessionCache = tls.NewLRUClientSessionCache(0)
		}
	}
}

// Client returns a functional option that allows you to bring your own http.Client
func Client(c *http.Client) func(*Attacker) {
	return func(a *Attacker) { a.client = *c }
}

// ProxyHeader returns a functional option that allows you to add your own
// Proxy CONNECT headers
func ProxyHeader(h http.Header) func(*Attacker) {
	return func(a *Attacker) {
		if tr, ok := a.client.Transport.(*http.Transport); ok {
			tr.ProxyConnectHeader = h
		}
	}
}

// ConnectTo returns a functional option which makes the attacker use the
// passed in map to translate target addr:port pairs. When used with DNSCaching,
// it must be used after it.
func ConnectTo(addrMap map[string][]string) func(*Attacker) {
	return func(a *Attacker) {
		if len(addrMap) == 0 {
			return
		}

		tr, ok := a.client.Transport.(*http.Transport)
		if !ok {
			return
		}

		dial := tr.DialContext
		if dial == nil {
			dial = a.dialer.DialContext
		}

		type roundRobin struct {
			addrs []string
			n     int
		}

		connectTo := make(map[string]*roundRobin, len(addrMap))
		for k, v := range addrMap {
			connectTo[k] = &roundRobin{addrs: v}
		}

		tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
			if cm, ok := connectTo[addr]; ok {
				cm.n = (cm.n + 1) % len(cm.addrs)
				addr = cm.addrs[cm.n]
			}
			return dial(ctx, network, addr)
		}
	}
}

// DNSCaching returns a functional option that enables DNS caching for
// the given ttl. When ttl is zero cached entries will never expire.
// When ttl is non-zero, this will start a refresh go-routine that updates
// the cache every ttl interval. This go-routine will be stopped when the
// attack is stopped.
// When the ttl is negative, no caching will be performed.
func DNSCaching(ttl time.Duration) func(*Attacker) {
	return func(a *Attacker) {
		if ttl < 0 {
			return
		}

		if tr, ok := a.client.Transport.(*http.Transport); ok {
			dial := tr.DialContext
			if dial == nil {
				dial = a.dialer.DialContext
			}

			resolver := &dnscache.Resolver{}

			if ttl != 0 {
				go func() {
					refresh := time.NewTicker(ttl)
					defer refresh.Stop()
					for {
						select {
						case <-refresh.C:
							resolver.Refresh(true)
						case <-a.stopch:
							return
						}
					}
				}()
			}

			rng := rand.New(rand.NewSource(time.Now().UnixNano()))

			tr.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, err error) {
				host, port, err := net.SplitHostPort(addr)
				if err != nil {
					return nil, err
				}

				ips, err := resolver.LookupHost(ctx, host)
				if err != nil {
					return nil, err
				}

				if len(ips) == 0 {
					return nil, &net.DNSError{Err: "no such host", Name: addr}
				}

				// Pick a random IP from each IP family and dial each concurrently.
				// The first that succeeds wins, the other gets canceled.

				rng.Shuffle(len(ips), func(i, j int) { ips[i], ips[j] = ips[j], ips[i] })

				ips = firstOfEachIPFamily(ips)

				type result struct {
					conn net.Conn
					err  error
				}

				ch := make(chan result, len(ips))
				ctx, cancel := context.WithCancel(ctx)
				defer cancel()

				for _, ip := range ips {
					go func(ip string) {
						conn, err := dial(ctx, network, net.JoinHostPort(ip, port))
						if err == nil {
							cancel()
						}
						ch <- result{conn, err}
					}(ip)
				}

				for i := 0; i < cap(ch); i++ {
					if r := <-ch; conn == nil {
						conn, err = r.conn, r.err
					}
				}

				return conn, err
			}
		}
	}
}

// firstOfEachIPFamily returns the first IP of each IP family in the input slice.
func firstOfEachIPFamily(ips []string) []string {
	if len(ips) == 0 {
		return ips
	}

	var (
		lastV4 bool
		each   = ips[:0]
	)

	for i := 0; i < len(ips) && len(each) < 2; i++ {
		ip := net.ParseIP(ips[i])
		if ip == nil {
			continue
		}

		isV4 := ip.To4() != nil
		if len(each) == 0 || isV4 != lastV4 {
			each = append(each, ips[i])
			lastV4 = isV4
		}
	}

	return each
}

type attack struct {
	name  string
	began time.Time

	seqmu sync.Mutex
	seq   uint64
}

// Attack reads its Targets from the passed Targeter and attacks them at
// the rate specified by the Pacer. When the duration is zero the attack
// runs until Stop is called. Results are sent to the returned channel as soon
// as they arrive and will have their Attack field set to the given name.
func (a *Attacker) Attack(tr Targeter, p Pacer, du time.Duration, name string) <-chan *Result {
	var wg sync.WaitGroup

	workers := a.workers
	if workers > a.maxWorkers {
		workers = a.maxWorkers
	}

	atk := &attack{
		name:  name,
		began: time.Now(),
	}

	results := make(chan *Result)
	ticks := make(chan struct{})
	for i := uint64(0); i < workers; i++ {
		wg.Add(1)
		go a.attack(tr, atk, &wg, ticks, results)
	}

	go func() {
		defer func() {
			close(ticks)
			wg.Wait()
			close(results)
			a.Stop()
		}()

		count := uint64(0)
		for {
			elapsed := time.Since(atk.began)
			if du > 0 && elapsed > du {
				return
			}

			wait, stop := p.Pace(elapsed, count)
			if stop {
				return
			}

			time.Sleep(wait)

			if workers < a.maxWorkers {
				select {
				case ticks <- struct{}{}:
					count++
					continue
				case <-a.stopch:
					return
				default:
					// all workers are blocked. start one more and try again
					workers++
					wg.Add(1)
					go a.attack(tr, atk, &wg, ticks, results)
				}
			}

			select {
			case ticks <- struct{}{}:
				count++
			case <-a.stopch:
				return
			}
		}
	}()

	return results
}

// Stop stops the current attack. The return value indicates whether this call
// has signalled the attack to stop (`true` for the first call) or whether it
// was a noop because it has been previously signalled to stop (`false` for any
// subsequent calls).
func (a *Attacker) Stop() bool {
	select {
	case <-a.stopch:
		return false
	default:
		a.stopOnce.Do(func() { close(a.stopch) })
		return true
	}
}

func (a *Attacker) attack(tr Targeter, atk *attack, workers *sync.WaitGroup, ticks <-chan struct{}, results chan<- *Result) {
	defer workers.Done()
	for range ticks {
		results <- a.hit(tr, atk)
	}
}

func (a *Attacker) hit(tr Targeter, atk *attack) *Result {
	var (
		res = Result{Attack: atk.name}
		tgt Target
		err error
	)

	//
	// Subtleness ahead! We need to compute the result timestamp in
	// the same critical section that protects the increment of the sequence
	// number because we want the same total ordering of timestamps and sequence
	// numbers. That is, we wouldn't want two results A and B where A.seq > B.seq
	// but A.timestamp < B.timestamp.
	//
	// Additionally, we calculate the result timestamp based on the same beginning
	// timestamp using the Add method, which will use monotonic time calculations.
	//
	atk.seqmu.Lock()
	res.Timestamp = atk.began.Add(time.Since(atk.began))
	res.Seq = atk.seq
	atk.seq++
	atk.seqmu.Unlock()

	defer func() {
		res.Latency = time.Since(res.Timestamp)
		if err != nil {
			res.Error = err.Error()
		}
	}()

	if err = tr(&tgt); err != nil {
		a.Stop()
		return &res
	}

	res.Method = tgt.Method
	res.URL = tgt.URL

	req, err := tgt.Request()
	if err != nil {
		return &res
	}

	if atk.name != "" {
		req.Header.Set("X-Vegeta-Attack", atk.name)
	}

	req.Header.Set("X-Vegeta-Seq", strconv.FormatUint(res.Seq, 10))

	if a.chunked {
		req.TransferEncoding = append(req.TransferEncoding, "chunked")
	}

	r, err := a.client.Do(req)
	if err != nil {
		return &res
	}
	defer r.Body.Close()

	body := io.Reader(r.Body)
	if a.maxBody >= 0 {
		body = io.LimitReader(r.Body, a.maxBody)
	}

	if res.Body, err = io.ReadAll(body); err != nil {
		return &res
	} else if _, err = io.Copy(io.Discard, r.Body); err != nil {
		return &res
	}

	res.BytesIn = uint64(len(res.Body))

	if req.ContentLength != -1 {
		res.BytesOut = uint64(req.ContentLength)
	}

	if res.Code = uint16(r.StatusCode); res.Code < 200 || res.Code >= 400 {
		res.Error = r.Status
	}

	res.Headers = r.Header

	return &res
}


================================================
FILE: lib/attack_fuzz.go
================================================
//go:build gofuzz
// +build gofuzz

package vegeta

import (
	"encoding/binary"
	"fmt"
	"net"
	"net/http"
	"os"
	"time"
)

// FuzzAttackerTCP fuzzes binary responses to attacker.
func FuzzAttackerTCP(fuzz []byte) int {
	// Ignore empty fuzz
	if len(fuzz) == 0 {
		return -1
	}

	// Start server
	directory, err := os.MkdirTemp("/tmp", "fuzz")
	if err != nil {
		panic(err.Error())
	}
	socket := fmt.Sprintf("%s/attacker.sock", directory)
	listener, err := net.Listen("unix", socket)
	if err != nil {
		panic(err.Error())
	}
	go func() {
		connection, err := listener.Accept()
		if err != nil {
			panic(err.Error())
		}
		_, err = connection.Write(fuzz)
		if err != nil {
			panic(err.Error())
		}
		err = connection.Close()
		if err != nil {
			panic(err.Error())
		}
	}()
	defer listener.Close()
	defer os.RemoveAll(directory)

	// Setup targeter
	targeter := Targeter(func(target *Target) error {
		target.Method = "GET"
		target.URL = "http://vegeta.test"
		return nil
	})

	// Deliver a single hit
	attacker := NewAttacker(
		UnixSocket(socket),
		Workers(1),
		MaxWorkers(1),
		Timeout(time.Second),
		KeepAlive(false),
	)
	result := attacker.hit(targeter, "fuzz")
	if result.Error != "" {
		return 0
	}
	return 1
}

// FuzzAttackerHTTP fuzzes valid HTTP responses to attacker.
func FuzzAttackerHTTP(fuzz []byte) int {
	// Decode response
	code, headers, body, ok := decodeFuzzResponse(fuzz)
	if !ok {
		return -1
	}

	// Start server
	directory, err := os.MkdirTemp("/tmp", "fuzz")
	if err != nil {
		panic(err.Error())
	}
	socket := fmt.Sprintf("%s/attacker.sock", directory)
	listener, err := net.Listen("unix", socket)
	if err != nil {
		panic(err.Error())
	}
	handler := func(response http.ResponseWriter, request *http.Request) {
		for name, values := range headers {
			for _, value := range values {
				response.Header().Add(name, value)
			}
		}
		response.WriteHeader(int(code))
		_, err := response.Write(body)
		if err != nil {
			panic(err.Error())
		}
	}
	server := http.Server{
		Handler: http.HandlerFunc(handler),
	}
	defer server.Close()
	defer listener.Close()
	defer os.RemoveAll(directory)
	go server.Serve(listener)

	// Setup targeter
	targeter := Targeter(func(target *Target) error {
		target.Method = "GET"
		target.URL = "http://vegeta.test"
		return nil
	})

	// Deliver a single hit
	attacker := NewAttacker(
		UnixSocket(socket),
		Workers(1),
		MaxWorkers(1),
		Timeout(time.Second),
		KeepAlive(false),
	)
	result := attacker.hit(targeter, "fuzz")
	if result.Error != "" {
		return 0
	}
	return 1
}

func decodeFuzzResponse(fuzz []byte) (
	code int,
	headers map[string][]string,
	body []byte,
	ok bool,
) {
	if len(fuzz) < 2 {
		return
	}
	headers = make(map[string][]string)
	body = []byte{}
	code = int(binary.LittleEndian.Uint16(fuzz[0:2]))
	if len(fuzz) == 2 {
		ok = true
		return
	}
	fuzz, ok = decodeFuzzHeaders(fuzz[2:], headers)
	if !ok {
		return
	}
	body = fuzz
	ok = true
	return
}


================================================
FILE: lib/attack_test.go
================================================
package vegeta

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"
)

func TestAttackRate(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
	)
	defer server.Close()
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	rate := Rate{Freq: 100, Per: time.Second}
	atk := NewAttacker()
	var hits uint64
	for range atk.Attack(tr, rate, 1*time.Second, "") {
		hits++
	}
	if got, want := hits, uint64(rate.Freq); got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

func TestAttackDuration(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
	)
	defer server.Close()

	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	atk := NewAttacker()
	rate := Rate{Freq: 100, Per: time.Second}

	var m Metrics
	for res := range atk.Attack(tr, rate, rate.Per, "") {
		m.Add(res)
	}
	m.Close()

	if got, want := m.Requests, uint64(rate.Freq); got != want {
		t.Errorf("got %v hits, want: %v", got, want)
	} else if got, want := m.Duration.Round(time.Second), time.Second; got != want {
		t.Errorf("got duration %s, want %s", got, want)
	}
}

func TestTLSConfig(t *testing.T) {
	atk := NewAttacker()
	got := atk.client.Transport.(*http.Transport).TLSClientConfig
	if want := (&tls.Config{InsecureSkipVerify: false}); !reflect.DeepEqual(got, want) {
		t.Fatalf("got: %+v, want: %+v", got, want)
	}
}

func TestRedirects(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			http.Redirect(w, r, "/redirect", 302)
		}),
	)
	defer server.Close()
	redirects := 2
	atk := NewAttacker(Redirects(redirects))
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	want := fmt.Sprintf("stopped after %d redirects", redirects)
	if got := res.Error; !strings.HasSuffix(got, want) {
		t.Fatalf("want: '%v' in '%v'", want, got)
	}
}

func TestNoFollow(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			http.Redirect(w, r, "/redirect-here", 302)
		}),
	)
	defer server.Close()
	atk := NewAttacker(Redirects(NoFollow))
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if res.Error != "" {
		t.Fatalf("got err: %v", res.Error)
	}
	if res.Code != 302 {
		t.Fatalf("res.Code => %d, want %d", res.Code, 302)
	}
}

func TestTimeout(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			<-time.After(20 * time.Millisecond)
		}),
	)
	defer server.Close()
	atk := NewAttacker(Timeout(10 * time.Millisecond))
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	res := atk.hit(tr, &attack{name: "", began: time.Now()})

	want := "Client.Timeout exceeded while awaiting headers"
	if got := res.Error; !strings.Contains(got, want) {
		t.Fatalf("want: '%v' in '%v'", want, got)
	}

	if res.Latency == 0 {
		t.Fatal("Latency wasn't captured with a timed-out result")
	}
}

func TestLocalAddr(t *testing.T) {
	t.Parallel()
	addr, err := net.ResolveIPAddr("ip", "127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if got, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
				t.Fatal(err)
			} else if want := addr.String(); got != want {
				t.Fatalf("wrong source address. got %v, want: %v", got, want)
			}
		}),
	)
	defer server.Close()
	atk := NewAttacker(LocalAddr(*addr))
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	atk.hit(tr, &attack{name: "", began: time.Now()})

}

func TestKeepAlive(t *testing.T) {
	t.Parallel()
	atk := NewAttacker(KeepAlive(false))
	if got, want := atk.dialer.KeepAlive, time.Duration(0); got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
	got := atk.client.Transport.(*http.Transport).DisableKeepAlives
	if want := true; got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

// This test cannot be run in parallel with TestTLSConfig() because ClientSessionCache
// is designed to be called concurrently from different goroutines.
func TestSessionTickets(t *testing.T) {
	atk := NewAttacker(SessionTickets(true))
	cf := atk.client.Transport.(*http.Transport).TLSClientConfig
	got, want := cf.SessionTicketsDisabled, false
	if got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
	if cf.ClientSessionCache == nil {
		t.Fatalf("ClientSessionCache is nil")
	}
}

func TestConnections(t *testing.T) {
	t.Parallel()
	atk := NewAttacker(Connections(23))
	got := atk.client.Transport.(*http.Transport).MaxIdleConnsPerHost
	if want := 23; got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

func TestStatusCodeErrors(t *testing.T) {
	t.Parallel()
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.WriteHeader(http.StatusBadRequest)
		}),
	)
	defer server.Close()
	atk := NewAttacker()
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})

	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if got, want := res.Error, "400 Bad Request"; got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

func TestBadTargeterError(t *testing.T) {
	t.Parallel()
	atk := NewAttacker()
	tr := func(*Target) error { return io.EOF }
	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if got, want := res.Error, io.EOF.Error(); got != want {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

func TestResponseBodyCapture(t *testing.T) {
	t.Parallel()

	want := []byte("VEGETA")
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write(want)
		}),
	)
	defer server.Close()
	atk := NewAttacker()
	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})

	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if got := res.Body; !bytes.Equal(got, want) {
		t.Fatalf("got: %v, want: %v", got, want)
	}
}

func TestProxyOption(t *testing.T) {
	t.Parallel()

	body := []byte("PROXIED!")
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write(body)
		}),
	)
	defer server.Close()

	proxyURL, err := url.Parse(server.URL)
	if err != nil {
		t.Fatal(err)
	}

	atk := NewAttacker(Proxy(func(r *http.Request) (*url.URL, error) {
		return proxyURL, nil
	}))

	tr := NewStaticTargeter(Target{Method: "GET", URL: "http://127.0.0.2"})
	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if got, want := res.Error, ""; got != want {
		t.Errorf("got error: %q, want %q", got, want)
	}

	if got, want := res.Body, body; !bytes.Equal(got, want) {
		t.Errorf("got body: %q, want: %q", got, want)
	}
}

func TestMaxBody(t *testing.T) {
	t.Parallel()

	body := []byte("VEGETA")
	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write(body)
		}),
	)
	defer server.Close()

	for i := DefaultMaxBody; i < int64(len(body)); i++ {
		maxBody := i
		t.Run(fmt.Sprint(maxBody), func(t *testing.T) {
			atk := NewAttacker(MaxBody(maxBody))
			tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
			res := atk.hit(tr, &attack{name: "", began: time.Now()})

			want := body
			if maxBody >= 0 {
				want = want[:maxBody]
			}

			if got := res.Body; !bytes.Equal(got, want) {
				t.Fatalf("got: %s, want: %s", got, want)
			}
		})
	}
}

func TestUnixSocket(t *testing.T) {
	t.Parallel()
	body := []byte("IT'S A UNIX SYSTEM, I KNOW THIS")

	socketDir, err := os.MkdirTemp("", "vegata")
	if err != nil {
		t.Fatal("Failed to create socket dir", err)
	}
	defer os.RemoveAll(socketDir)
	socketFile := filepath.Join(socketDir, "test.sock")

	unixListener, err := net.Listen("unix", socketFile)

	if err != nil {
		t.Fatal("Failed to listen on unix socket", err)
	}

	server := http.Server{
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write(body)
		}),
	}
	defer server.Close()

	go server.Serve(unixListener)

	start := time.Now()
	for {
		if time.Since(start) > 1*time.Second {
			t.Fatal("Server didn't listen on unix socket in time")
		}
		_, err := os.Stat(socketFile)
		if err == nil {
			break
		} else if os.IsNotExist(err) {
			time.Sleep(10 * time.Millisecond)
		} else {
			t.Fatal("unexpected error from unix socket", err)
		}
	}

	atk := NewAttacker(UnixSocket(socketFile))

	tr := NewStaticTargeter(Target{Method: "GET", URL: "http://anyserver/"})
	res := atk.hit(tr, &attack{name: "", began: time.Now()})
	if !bytes.Equal(res.Body, body) {
		t.Fatalf("got: %s, want: %s", string(res.Body), string(body))
	}
}

func TestClient(t *testing.T) {
	t.Parallel()

	dialer := &net.Dialer{
		LocalAddr: &net.TCPAddr{IP: DefaultLocalAddr.IP, Zone: DefaultLocalAddr.Zone},
		KeepAlive: 30 * time.Second,
	}

	client := &http.Client{
		Timeout: 1 * time.Nanosecond,
		Transport: &http.Transport{
			Proxy:               http.ProxyFromEnvironment,
			DialContext:         dialer.DialContext,
			TLSClientConfig:     DefaultTLSConfig,
			MaxIdleConnsPerHost: DefaultConnections,
		},
	}

	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			select {}
		}),
	)
	defer server.Close()

	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})

	atk := NewAttacker(Client(client))
	resp := atk.hit(tr, &attack{name: "TEST", began: time.Now()})
	if !strings.Contains(resp.Error, "Client.Timeout exceeded while awaiting headers") {
		t.Errorf("Expected timeout error")
	}
}

func TestVegetaHeaders(t *testing.T) {
	t.Parallel()

	server := httptest.NewServer(
		http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			_ = json.NewEncoder(w).Encode(r.Header)
		}),
	)

	defer server.Close()

	tr := NewStaticTargeter(Target{Method: "GET", URL: server.URL})
	a := NewAttacker()
	atk := &attack{name: "ig-bang", began: time.Now()}
	for seq := 0; seq < 5; seq++ {
		res := a.hit(tr, atk)

		var hdr http.Header
		if err := json.Unmarshal(res.Body, &hdr); err != nil {
			t.Fatal(err)
		}

		if have, want := hdr.Get("X-Vegeta-Attack"), atk.name; have != want {
			t.Errorf("X-Vegeta-Attack: have %q, want %q", have, want)
		}

		if have, want := hdr.Get("X-Vegeta-Seq"), strconv.Itoa(seq); have != want {
			t.Errorf("X-Vegeta-Seq: have %q, want %q", have, want)
		}
	}
}

// https://github.com/tsenart/vegeta/issues/649
func TestDNSCaching_Issue649(t *testing.T) {
	defer func() {
		if err := recover(); err != nil {
			t.Fatalf("panic: %v", err)
		}
	}()

	tr := NewStaticTargeter(Target{Method: "GET", URL: "https://[2a00:1450:4005:802::200e]"})
	atk := NewAttacker(DNSCaching(0))
	_ = atk.hit(tr, &attack{name: "TEST", began: time.Now()})
}

func TestFirstOfEachIPFamily(t *testing.T) {
	tests := []struct {
		name  string
		input []string
		want  []string
	}{
		{
			name:  "empty list",
			input: []string{},
			want:  []string{},
		},
		{
			name:  "single IPv4",
			input: []string{"192.168.1.1"},
			want:  []string{"192.168.1.1"},
		},
		{
			name:  "single IPv6",
			input: []string{"fe80::1"},
			want:  []string{"fe80::1"},
		},
		{
			name:  "multiple IPv6",
			input: []string{"fe80::1", "fe80::2"},
			want:  []string{"fe80::1"},
		},
		{
			name:  "one IPv4 and one IPv6",
			input: []string{"192.168.1.1", "fe80::1"},
			want:  []string{"192.168.1.1", "fe80::1"},
		},
		{
			name:  "one IPv6 and one IPv4",
			input: []string{"fe80::1", "192.168.1.1"},
			want:  []string{"fe80::1", "192.168.1.1"},
		},
		{
			name:  "multiple IPs with alternating versions",
			input: []string{"192.168.1.1", "fe80::1", "192.168.1.2", "fe80::2"},
			want:  []string{"192.168.1.1", "fe80::1"},
		},
		{
			name:  "multiple IPs with same versions",
			input: []string{"192.168.1.1", "192.168.1.2", "192.168.1.3"},
			want:  []string{"192.168.1.1"},
		},
		{
			name:  "multiple IPs with non-alternating versions",
			input: []string{"192.168.1.1", "fe80::1", "192.168.1.2", "192.168.1.3", "fe80::2"},
			want:  []string{"192.168.1.1", "fe80::1"},
		},
		{
			name:  "invalid IP addresses",
			input: []string{"invalid", "192.168.1.1", "fe80::1"},
			want:  []string{"192.168.1.1", "fe80::1"},
		},
		{
			name:  "IPv4 with embedded IPv6",
			input: []string{"192.168.1.1", "::ffff:c000:280", "fe80::1"},
			want:  []string{"192.168.1.1", "fe80::1"},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := firstOfEachIPFamily(tt.input)
			if len(result) != len(tt.want) {
				t.Fatalf("want %v, got %v", tt.want, result)
			}
			if diff := cmp.Diff(tt.want, result); diff != "" {
				t.Errorf("unexpected result (-want +got):\n%s", diff)
			}
		})
	}
}

func TestAttackConnectTo(t *testing.T) {
	t.Parallel()
	var mu sync.Mutex
	hits := make(map[string]int)
	srvs := make(map[string]int)

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		mu.Lock()
		hits[r.Host]++
		mu.Unlock()
	})

	addrs := make([]string, 3)
	for i := range addrs {
		ln, err := net.Listen("tcp", "127.0.0.1:0")
		if err != nil {
			t.Fatal(err)
		}
		addrs[i] = ln.Addr().String()

		srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			mu.Lock()
			srvs[ln.Addr().String()]++
			mu.Unlock()
			handler.ServeHTTP(w, r)
		}))

		srv.Listener = ln
		srv.Start()
		t.Cleanup(srv.Close)
	}

	tr := NewStaticTargeter(
		Target{Method: "GET", URL: "http://sapo.pt:80"},
		Target{Method: "GET", URL: "http://sapo.pt:80"},
		Target{Method: "GET", URL: "http://sapo.pt:80"},
		Target{Method: "GET", URL: "http://" + addrs[0]},
	)

	atk := NewAttacker(
		KeepAlive(false),
		ConnectTo(map[string][]string{"sapo.pt:80": addrs}),
	)

	a := &attack{name: "TEST", began: time.Now()}
	for i := 0; i < 4; i++ {
		resp := atk.hit(tr, a)
		if resp.Error != "" {
			t.Fatal(resp.Error)
		}
	}

	want := map[string]int{"sapo.pt:80": 3, addrs[0]: 1}
	if diff := cmp.Diff(want, hits); diff != "" {
		t.Errorf("unexpected hits (-want +got):\n%s", diff)
	}

	want = map[string]int{addrs[0]: 2, addrs[1]: 1, addrs[2]: 1}
	if diff := cmp.Diff(want, srvs); diff != "" {
		t.Errorf("unexpected hits (-want +got):\n%s", diff)
	}
}


================================================
FILE: lib/histogram.go
================================================
package vegeta

import (
	"bytes"
	"fmt"
	"strings"
	"time"
)

// Buckets represents an Histogram's latency buckets.
type Buckets []time.Duration

// Histogram is a bucketed latency Histogram.
type Histogram struct {
	Buckets Buckets
	Counts  []uint64
	Total   uint64
}

// Add implements the Add method of the Report interface by finding the right
// Bucket for the given Result latency and increasing its count by one as well
// as the total count.
func (h *Histogram) Add(r *Result) {
	if len(h.Counts) != len(h.Buckets) {
		h.Counts = make([]uint64, len(h.Buckets))
	}

	var i int
	for ; i < len(h.Buckets)-1; i++ {
		if r.Latency >= h.Buckets[i] && r.Latency < h.Buckets[i+1] {
			break
		}
	}

	h.Total++
	h.Counts[i]++
}

// MarshalJSON returns a JSON encoding of the buckets and their counts.
func (h *Histogram) MarshalJSON() ([]byte, error) {
	var buf bytes.Buffer

	// Custom marshalling to guarantee order.
	buf.WriteString("{")
	for i := range h.Buckets {
		if i > 0 {
			buf.WriteString(", ")
		}
		if _, err := fmt.Fprintf(&buf, "\"%d\": %d", h.Buckets[i], h.Counts[i]); err != nil {
			return nil, err
		}
	}
	buf.WriteString("}")

	return buf.Bytes(), nil
}

// Nth returns the nth bucket represented as a string.
func (bs Buckets) Nth(i int) (left, right string) {
	if i >= len(bs)-1 {
		return bs[i].String(), "+Inf"
	}
	return bs[i].String(), bs[i+1].String()
}

// UnmarshalText implements the encoding.TextUnmarshaler interface.
func (bs *Buckets) UnmarshalText(value []byte) error {
	if len(value) < 2 || value[0] != '[' || value[len(value)-1] != ']' {
		return fmt.Errorf("bad buckets: %s", value)
	}
	for i, v := range strings.Split(string(value[1:len(value)-1]), ",") {
		d, err := time.ParseDuration(strings.TrimSpace(v))
		if err != nil {
			return err
		}
		// add a default range of [0-Buckets[0]) if needed
		if i == 0 && d > 0 {
			*bs = append(*bs, 0)
		}
		*bs = append(*bs, d)
	}
	if len(*bs) == 0 {
		return fmt.Errorf("bad buckets: %s", value)
	}
	return nil
}


================================================
FILE: lib/histogram_test.go
================================================
package vegeta

import (
	"reflect"
	"testing"
	"time"
)

func TestHistogram_Add(t *testing.T) {
	t.Parallel()
	hist := Histogram{
		Buckets: []time.Duration{
			0,
			10 * time.Millisecond,
			25 * time.Millisecond,
			50 * time.Millisecond,
			100 * time.Millisecond,
			1000 * time.Millisecond,
		},
	}

	for _, d := range []time.Duration{
		5 * time.Millisecond,
		15 * time.Millisecond,
		30 * time.Millisecond,
		75 * time.Millisecond,
		200 * time.Millisecond,
		2000 * time.Millisecond,
	} {
		hist.Add(&Result{Latency: d})
	}

	if got, want := hist.Counts, []uint64{1, 1, 1, 1, 1, 1}; !reflect.DeepEqual(got, want) {
		t.Errorf("Counts: got: %v, want: %v", got, want)
	}

	if got, want := hist.Total, uint64(6); got != want {
		t.Errorf("Total: got %v, want: %v", got, want)
	}
}

func TestBuckets_UnmarshalText(t *testing.T) {
	t.Parallel()
	for value, want := range map[string]string{
		"":       "bad buckets: ",
		" ":      "bad buckets:  ",
		"{0, 2}": "bad buckets: {0, 2}",
		"[]":     `time: invalid duration ""`,
		"[0, 2]": `time: missing unit in duration "2"`,
	} {
		if got := (&Buckets{}).UnmarshalText([]byte(value)).Error(); got != want {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}

	for value, want := range map[string]Buckets{
		"[0,5ms]":             {0, 5 * time.Millisecond},
		"[0, 5ms]":            {0, 5 * time.Millisecond},
		"[   0,5ms, 10m    ]": {0, 5 * time.Millisecond, 10 * time.Minute},
		"[3ms,10ms]":          {0, 3 * time.Millisecond, 10 * time.Millisecond},
	} {
		var got Buckets
		if err := got.UnmarshalText([]byte(value)); err != nil {
			t.Fatal(err)
		} else if !reflect.DeepEqual(got, want) {
			t.Errorf("got: %v, want: %v", got, want)
		}
	}
}


================================================
FILE: lib/lttb/lttb.go
================================================
package lttb

import "errors"

// A Point in a line chart.
type Point struct{ X, Y float64 }

// An Iter is an iterator function that returns
// count number of Points or an error.
type Iter func(count int) ([]Point, error)

// Downsample `count` number of data points retrieved from the given iterator
// function to contain only `threshold` number of points while maintaining close
// visual similarity to the original data. The algorithm is called
// Largest-Triangle-Three-Buckets and is described in:
// https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf
//
// This implementation grew out of https://github.com/dgryski/go-lttb
// to limit memory usage by leveraging iterators.
func Downsample(count, threshold int, it Iter) ([]Point, error) {
	if threshold >= count || threshold == 0 {
		points, err := it(count)
		return points, err
	}

	if threshold < 3 {
		return nil, errors.New("lttb: min threshold is 3")
	}

	// Bucket size. Leave room for start and end data points
	size := float64(count-2) / float64(threshold-2)

	// Get the first point and the current bucket.
	points, err := it(int(1 + size))
	if err != nil {
		return nil, err
	}

	samples := make([]Point, 0, threshold)
	samples = append(samples, points[0]) // Always add the first point
	current := points[1:]

	for i := 0; i < threshold-2; i++ {
		// Calculate bucket boundaries (non inclusive hi)
		lo := int(float64(i+1)*size) + 1
		hi := int(float64(i+2)*size) + 1

		next, err := it(hi - lo)
		if err != nil {
			return nil, err
		}

		samples = append(samples, sample(samples[len(samples)-1], current, next))
		current = next
	}

	// Always add the last point unmodified
	if points, err = it(count - len(samples)); err != nil {
		return nil, err
	} else if len(points) == 0 {
		points = current
	}

	if len(points) > 0 {
		samples = append(samples, points[len(points)-1])
	}

	return samples, nil
}

func sample(a Point, current, next []Point) (b Point) {
	// Calculate point c as the average point of all points in the next bucket.
	var c Point
	for i := range next {
		c.X, c.Y = c.X+next[i].X, c.Y+next[i].Y
	}

	length := float64(len(next))
	c.X, c.Y = c.X/length, c.Y/length

	// Find index of point b that together with points a and c forms the largest triangle
	// amongst all points in the current bucket.
	var largest float64
	var index int
	for i, p := range current {
		// Calculate triangle area over three buckets
		area := (a.X-c.X)*(p.Y-a.Y) - (a.X-p.X)*(c.Y-a.Y)

		// We only care about the relative area here. Calling math.Abs() is slower than squaring.
		if area *= area; area > largest {
			largest, index = area, i
		}
	}

	return current[index]
}


================================================
FILE: lib/lttb/lttb_test.go
================================================
package lttb

import (
	"fmt"
	"reflect"
	"sync"
	"testing"
	"unsafe"

	golttb "github.com/dgryski/go-lttb"
	"github.com/google/go-cmp/cmp"
)

func TestDownsample(t *testing.T) {
	t.Parallel()

	for _, threshold := range []int{0, len(points[0]), len(points[0]) + 1} {
		have, err := Downsample(len(points[0]), threshold, newIterator(points[0]))
		if err != nil {
			t.Fatalf("threshold-%d: got err: %v", threshold, err)
		}

		want := points[0]
		if diff := cmp.Diff(have, want, cmp.AllowUnexported(Point{})); diff != "" {
			t.Errorf("threshold-%d: %s", threshold, diff)
		}
	}

	for i := 1; i < 3; i++ {
		threshold := i
		_, err := Downsample(len(points[0]), threshold, newIterator(points[0]))
		if have, want := fmt.Sprint(err), "lttb: min threshold is 3"; have != want {
			t.Errorf("threshold-%d: have err: %v, want %v", threshold, have, want)
		}
	}

	var wg sync.WaitGroup
	for i, ps := range points {
		for threshold := 3; threshold < len(ps); threshold++ {
			wg.Add(1)
			i, ps, threshold := i, ps, threshold
			go func() {
				defer wg.Done()

				msg := func(fmtstr string, args ...interface{}) string {
					return fmt.Sprintf(
						"points=%d len=%d threshold=%d: "+fmtstr,
						append([]interface{}{i, len(ps), threshold}, args...)...,
					)
				}

				ours, err := Downsample(len(ps), threshold, newIterator(ps))
				if err != nil {
					t.Error(msg("error: %v", err))
				}

				if have, want := len(ours), threshold; have != want {
					t.Error(msg("len(samples) != threshold: have %d, want %d", have, want))
				}

				if have, want := ours[0], ps[0]; have != want {
					t.Error(msg("samples[0] != data[0]: have %v, want %v", have, want))
				}

				if have, want := ours[len(ours)-1], ps[len(ps)-1]; have != want {
					t.Error(msg("samples[-1] != data[-1]: have %v, want %v", have, want))
				}

				// Test LTTB algorithm's equivalence to dgrisky/go-lttb
				in := *(*[]golttb.Point[float64])(unsafe.Pointer(&ps)) // #skipcq: GSC-G103
				out := golttb.LTTB(in, threshold)
				theirs := *(*[]Point)(unsafe.Pointer(&out)) // #skipcq: GSC-G103

				if !reflect.DeepEqual(ours, theirs) {
					t.Error(msg(cmp.Diff(ours, theirs, cmp.AllowUnexported(Point{}))))
				}
			}()
		}
	}

	wg.Wait()
}

func BenchmarkLTTB(b *testing.B) {
	data := *(*[]golttb.Point[float64])(unsafe.Pointer(&points[0])) // #skipcq: GSC-G103
	b.Run("dgryski", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			golttb.LTTB(data, 1000)
		}
	})

	b.Run("tsenart", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			Downsample(len(data), 1000, newIterator(points[0]))
		}
	})
}

func newIterator(data []Point) Iter {
	return func(count int) ([]Point, error) {
		if count > len(data) {
			count = len(data)
		}
		ps := data[:count]
		data = data[count:]
		return ps, nil
	}
}

// From https://raw.githubusercontent.com/sveinn-steinarsson/flot-downsample/master/demo_data.js
var points = [][]Point{
	{
		{0, 29.357995947822218},
		{1, 29.40932479606209},
		{2, 29.28168582006162},
		{3, 30.409965579108867},
		{4, 30.7726859735917},
		{5, 30.839942247539028},
		{6, 30.760611642264667},
		{7, 31.203663004229718},
		{8, 31.38899603525572},
		{9, 30.890299916955737},
		{10, 30.467811944911556},
		{11, 30.596837868069542},
		{12, 30.59789593509767},
		{13, 30.19693062465079},
		{14, 29.89081330734553},
		{15, 29.54668002901058},
		{16, 29.54890739422219},
		{17, 30.53743760171474},
		{18, 30.74066032317061},
		{19, 30.3774450601516},
		{20, 30.095148889986568},
		{21, 30.057979182917986},
		{22, 30.364655421168525},
		{23, 30.293450053773604},
		{24, 30.14578230340987},
		{25, 30.277772879951996},
		{26, 30.3711931235659},
		{27, 30.355932660992572},
		{28, 29.994740831603046},
		{29, 29.938012885023657},
		{30, 29.557268760451187},
		{31, 29.16161297604625},
		{32, 29.6921163421055},
		{33, 30.246270628292226},
		{34, 30.210955154680928},
		{35, 29.382964668934058},
		{36, 29.52892023906641},
		{37, 29.719742065732202},
		{38, 30.013856636945924},
		{39, 29.818636169776926},
		{40, 27.931224826933345},
		{41, 28.103057873678374},
		{42, 28.276025902356782},
		{43, 28.193497487789774},
		{44, 28.22099171488288},
		{45, 28.06872431241809},
		{46, 27.239835885250365},
		{47, 26.606504358317906},
		{48, 27.220308136213916},
		{49, 25.80790898978574},
		{50, 26.060334838062595},
		{51, 25.89611036822564},
		{52, 25.824433242208308},
		{53, 25.89212193260212},
		{54, 27.28963669872412},
		{55, 27.208259984780806},
		{56, 27.298211480886604},
		{57, 27.056163307023077},
		{58, 26.434701869643924},
		{59, 26.21938188318228},
		{60, 26.402877759468772},
		{61, 26.326019357967294},
		{62, 27.592635104460253},
		{63, 27.597468405434316},
		{64, 27.533410081050647},
		{65, 27.30713964830731},
		{66, 27.170789712751404},
		{67, 27.610166301145746},
		{68, 27.619847332319885},
		{69, 27.55974343996647},
		{70, 28.168803492093716},
		{71, 28.284229862452584},
		{72, 28.292638086760352},
		{73, 28.523718178262335},
		{74, 28.52268591410558},
		{75, 28.576637206595993},
		{76, 27.763715461946813},
		{77, 27.48488075310065},
		{78, 27.304006460281794},
		{79, 26.902025619666333},
		{80, 26.690162079132378},
		{81, 26.52277286738866},
		{82, 26.09406789919051},
		{83, 26.029039984983562},
		{84, 26.145181108429618},
		{85, 24.75335912549342},
		{86, 24.787772395126176},
		{87, 24.966652093726385},
		{88, 25.33621421606084},
		{89, 25.29283081429076},
		{90, 25.427452306231707},
		{91, 25.34334450564347},
		{92, 25.971939771661045},
		{93, 25.907910638400836},
		{94, 25.971895864171003},
		{95, 26.448419417928317},
		{96, 26.461057396494514},
		{97, 26.332417666691025},
		{98, 26.17395667752311},
		{99, 25.318121919340044},
		{100, 26.092918888834987},
		{101, 26.080903284583307},
		{102, 26.65713935644778},
		{103, 26.90227335392346},
		{104, 27.14904791481757},
		{105, 27.45775156727039},
		{106, 28.476933177720472},
		{107, 27.899526884805073},
		{108, 27.274094274806096},
		{109, 27.007320452528134},
		{110, 27.767594298696466},
		{111, 28.669197835798027},
		{112, 28.78287095361503},
		{113, 28.744062941208348},
		{114, 29.266136201836588},
		{115, 29.29631346563548},
		{116, 29.30576721224685},
		{117, 28.92417256867908},
		{118, 29.172020952087326},
		{119, 29.36572118529946},
		{120, 29.407882394097168},
		{121, 29.24581675687127},
		{122, 30.374496989862006},
		{123, 29.75867484229172},
		{124, 29.724977349500893},
		{125, 29.766232845230032},
		{126, 29.755425025733203},
		{127, 29.891515813029994},
		{128, 29.224842590902917},
		{129, 29.19894861750696},
		{130, 28.877260649054524},
		{131, 29.100160763856657},
		{132, 29.11303194254891},
		{133, 29.471499370130353},
		{134, 29.725430707066725},
		{135, 29.875645922022283},
		{136, 29.32336837740634},
		{137, 29.659223458914788},
		{138, 29.916122460150415},
		{139, 29.947591268372232},
		{140, 29.912720660976237},
		{141, 30.030001305562784},
		{142, 30.01603062688162},
		{143, 30.206305874273855},
		{144, 29.654798308068155},
		{145, 29.51005186796388},
		{146, 29.479249298103124},
		{147, 29.50465455692649},
		{148, 28.668390496723326},
		{149, 29.70235193454973},
		{150, 29.651621644229916},
		{151, 29.514646394709878},
		{152, 29.506006233800203},
		{153, 29.85094476486748},
		{154, 29.815453456016304},
		{155, 29.942433471924208},
		{156, 29.690047803042003},
		{157, 29.081114874079432},
		{158, 29.064499954878283},
		{159, 29.17427761652929},
		{160, 28.48135454514647},
		{161, 28.43614347392514},
		{162, 28.615830690136196},
		{163, 27.244815449582045},
		{164, 28.030839937141593},
		{165, 28.09433740820739},
		{166, 28.134090510807432},
		{167, 28.333335545414524},
		{168, 28.187860385951467},
		{169, 28.275647207865163},
		{170, 28.110663780904385},
		{171, 27.941108395946074},
		{172, 27.155839334130572},
		{173, 27.486338387798014},
		{174, 27.822551655905976},
		{175, 27.863745721980674},
		{176, 27.51492123912736},
		{177, 27.83845450366903},
		{178, 27.143346163904276},
		{179, 26.470510229480666},
		{180, 27.030260699355054},
		{181, 26.530046883178517},
		{182, 26.061343714664623},
		{183, 26.451944204073293},
		{184, 26.430516873002972},
		{185, 27.54560649645601},
		{186, 27.607455732128237},
		{187, 27.3151823435893},
		{188, 27.015508353290546},
		{189, 27.564104270774138},
		{190, 27.401004407024764},
		{191, 27.158236015306873},
		{192, 27.15560082391509},
		{193, 27.052060260660955},
		{194, 27.170854273897024},
		{195, 27.764649442110628},
		{196, 28.37485762180034},
		{197, 28.693644963914128},
		{198, 28.639988945921225},
		{199, 28.55415913033328},
		{200, 28.227269873938933},
		{201, 28.17193587609251},
		{202, 28.326544342536973},
		{203, 27.64207374329132},
		{204, 28.28132114918632},
		{205, 28.87895845286964},
		{206, 28.188530355189847},
		{207, 27.543826104728634},
		{208, 27.518668557969406},
		{209, 27.501005443892083},
		{210, 27.4034023213343},
		{211, 27.81919230719886},
		{212, 28.51752545491846},
		{213, 28.45642871817993},
		{214, 28.281434136230057},
		{215, 28.955222450571647},
		{216, 28.817758413114476},
		{217, 28.512855374048605},
		{218, 28.53649013938214},
		{219, 28.037741647416063},
		{220, 28.758762367232816},
		{221, 28.411225526795217},
		{222, 28.081382658095393},
		{223, 28.018197966678386},
		{224, 27.669840575416934},
		{225, 27.729482622798493},
		{226, 27.44804950151258},
		{227, 27.057357503159633},
		{228, 27.02667664651584},
		{229, 26.99034079421472},
		{230, 27.624460374012415},
		{231, 26.6107079586933},
		{232, 26.586632740266342},
		{233, 26.50503068257422},
		{234, 26.528094947562206},
		{235, 27.42586110225183},
		{236, 27.58607997646959},
		{237, 27.119751888180552},
		{238, 27.08687612699868},
		{239, 26.50890594997075},
		{240, 27.31126847238326},
		{241, 27.241646652930587},
		{242, 27.206837899664286},
		{243, 27.806910729195003},
		{244, 27.943871889687294},
		{245, 27.682133734768627},
		{246, 27.717567280916626},
		{247, 28.50754775235408},
		{248, 28.522618646129153},
		{249, 28.119450170073687},
		{250, 28.142446798473102},
		{251, 27.493875384325104},
		{252, 27.232866008532874},
		{253, 26.815819408391537},
		{254, 26.66806605894335},
		{255, 26.832795316319906},
		{256, 26.6709072973403},
		{257, 26.805339614467922},
		{258, 25.87709141573906},
		{259, 25.78663848060838},
		{260, 26.292688529709856},
		{261, 26.13540568260593},
		{262, 26.950679537489023},
		{263, 26.74360016328177},
		{264, 25.880978465490344},
		{265, 26.625349316487267},
		{266, 27.726596358113618},
		{267, 27.678660195691705},
		{268, 27.712915567796777},
		{269, 27.721698306913026},
		{270, 27.905267233295028},
		{271, 27.957187159455156},
		{272, 27.858194094400584},
		{273, 28.081932932040928},
		{274, 27.735044748607958},
		{275, 27.032793497721116},
		{276, 27.507939311361685},
		{277, 27.574645954142067},
		{278, 27.574051095225684},
		{279, 27.759761781417595},
		{280, 27.365795276665352},
		{281, 26.617667215269847},
		{282, 26.798097033417232},
		{283, 26.195989054524656},
		{284, 26.976938134909243},
		{285, 26.89198848346594},
		{286, 27.147250351373707},
		{287, 27.43948527543756},
		{288, 28.0008367927751},
		{289, 28.231697069321097},
		{290, 28.7967810312443},
		{291, 29.512759843423506},
		{292, 29.41555351035952},
		{293, 30.70537467842703},
		{294, 30.332009655179892},
		{295, 30.368538690398843},
		{296, 30.73440265654596},
		{297, 30.967799052657455},
		{298, 31.22392323854322},
		{299, 31.122470949743033},
		{300, 31.140432351354303},
		{301, 31.13729855237942},
		{302, 30.716789453632746},
		{303, 31.055606178854195},
		{304, 31.025310612429436},
		{305, 30.746317663776093},
		{306, 31.16989662941391},
		{307, 29.623226075091324},
		{308, 29.11707721446215},
		{309, 29.671462419401518},
		{310, 29.32656872224774},
		{311, 29.360034344664133},
		{312, 30.193073601940906},
		{313, 30.051282853224887},
		{314, 30.094809176026143},
		{315, 30.62616938793058},
		{316, 31.24738345775188},
		{317, 31.288951935975373},
		{318, 30.793680071961138},
		{319, 30.855230722079575},
		{320, 30.172789122099953},
		{321, 30.16588226960243},
		{322, 30.02896795596743},
		{323, 28.710256908027688},
		{324, 28.788445957400086},
		{325, 29.14084131034792},
		{326, 29.154793392113767},
		{327, 29.509956518244064},
		{328, 29.919766479376083},
		{329, 30.809790278228583},
		{330, 31.51994434827819},
		{331, 31.14360887134284},
		{332, 30.960009728867895},
		{333, 31.007757592227232},
		{334, 29.912529162927882},
		{335, 30.430549132609936},
		{336, 30.286270410087386},
		{337, 30.29853067098949},
		{338, 30.28484502358319},
		{339, 30.2649148646112},
		{340, 30.269814084876984},
		{341, 29.48743777656781},
		{342, 29.25324229055582},
		{343, 29.3224085984498},
		{344, 28.845749148292715},
		{345, 28.25734414947841},
		{346, 28.22244460496951},
		{347, 28.212727797755832},
		{348, 28.099709252761244},
		{349, 28.157686542165766},
		{350, 28.15110192590233},
		{351, 28.242118337655835},
		{352, 29.53367482995351},
		{353, 29.532585019641683},
		{354, 29.943653842668887},
		{355, 28.64740678713178},
		{356, 28.627878421859094},
		{357, 28.85948017439502},
		{358, 29.421837208187565},
		{359, 29.213674689162733},
		{360, 29.588524659441383},
		{361, 29.871736651370572},
		{362, 29.97536581410366},
		{363, 29.090848126781193},
		{364, 29.07367624649577},
		{365, 28.936182688349078},
		{366, 28.478980562612755},
		{367, 27.701450632319055},
		{368, 27.70314463302395},
		{369, 27.690633468393905},
		{370, 27.712418470005847},
		{371, 28.04360951096915},
		{372, 27.899319369636174},
		{373, 27.67953057101954},
		{374, 27.33713099741098},
		{375, 27.715275282261704},
		{376, 27.09457980740444},
		{377, 26.564904718909652},
		{378, 26.851805720484524},
		{379, 27.17971899490677},
		{380, 27.203035420946204},
		{381, 26.98833921789535},
		{382, 27.3376969508508},
		{383, 27.36673199620505},
		{384, 27.22367712016426},
		{385, 27.295774446517406},
		{386, 27.24426813335004},
		{387, 27.804345559349205},
		{388, 27.81107241888124},
		{389, 28.007141902081127},
		{390, 28.196204812447014},
		{391, 27.570724094739713},
		{392, 28.353947742891283},
		{393, 28.264285808134655},
		{394, 28.001544074943496},
		{395, 28.073693599174273},
		{396, 28.13948170648531},
		{397, 27.7246917685699},
		{398, 27.372056917732422},
		{399, 26.76664288679182},
		{400, 26.726530330089947},
		{401, 26.73659456496834},
		{402, 26.35282363879538},
		{403, 26.953655414803745},
		{404, 27.037728660238816},
		{405, 26.391122852260175},
		{406, 26.45637305967239},
		{407, 25.78486318168484},
		{408, 25.92078676697798},
		{409, 26.4970571420541},
		{410, 25.86809752383717},
		{411, 26.534413662015773},
		{412, 27.226357547185447},
		{413, 26.71252553894152},
		{414, 26.435002451423312},
		{415, 26.921455461481504},
		{416, 27.06045686220195},
		{417, 27.09418382303274},
		{418, 28.011098852919908},
		{419, 27.896959438752912},
		{420, 27.914042725695705},
		{421, 27.547368437091734},
		{422, 26.710013475304418},
		{423, 26.67332778875601},
		{424, 26.624659424882857},
		{425, 26.57172379809563},
		{426, 26.846697174621756},
		{427, 25.8834697613218},
		{428, 26.0400273638686},
		{429, 25.922770964698366},
		{430, 26.550977646141284},
		{431, 26.7196171595444},
		{432, 26.57693368973477},
		{433, 26.754937488902705},
		{434, 26.68923906981248},
		{435, 27.578054073124644},
		{436, 28.491944955522996},
		{437, 29.462067517762534},
		{438, 29.049663449716007},
		{439, 29.29125398211083},
		{440, 29.716399938469106},
		{441, 29.697795912329543},
		{442, 28.842426341018918},
		{443, 27.995794268014496},
		{444, 27.568707173494055},
		{445, 27.572194900322412},
		{446, 28.94876289646488},
		{447, 28.827587778805206},
		{448, 28.20122725800809},
		{449, 28.982543824618322},
		{450, 28.98764510982713},
		{451, 28.476638374330257},
		{452, 27.8971845311884},
		{453, 28.357599004387694},
		{454, 29.550067169716076},
		{455, 29.059986913307316},
		{456, 29.44698201092504},
		{457, 29.444893222605785},
		{458, 30.2987283695555},
		{459, 30.490753195685443},
		{460, 30.3712818585665},
		{461, 31.03092246398632},
		{462, 31.1306416649066},
		{463, 31.204020755490298},
		{464, 31.302761670091414},
		{465, 31.287884426895985},
		{466, 30.49414678626753},
		{467, 30.9842218570926},
		{468, 30.88247586217915},
		{469, 31.65627890749247},
		{470, 31.300373482363312},
		{471, 31.009412915052188},
		{472, 31.135319385771062},
		{473, 31.142947189076295},
		{474, 31.095825728106682},
		{475, 31.402733294236572},
		{476, 31.348161546083656},
		{477, 31.600766880442425},
		{478, 31.51732023898528},
		{479, 31.218212979786024},
		{480, 31.431310499487758},
		{481, 31.536799819023997},
		{482, 31.590576295671646},
		{483, 31.49429616322668},
		{484, 32.1816892011556},
		{485, 32.61239327037908},
		{486, 32.69902576477615},
		{487, 32.89146487332367},
		{488, 33.87564290993047},
		{489, 33.89045560640269},
		{490, 33.8295470579556},
		{491, 33.83070162926511},
		{492, 33.57726370546161},
		{493, 33.80516778960143},
		{494, 34.26212065396207},
		{495, 34.4134739195819},
		{496, 34.72554255082181},
		{497, 34.7082104992009},
		{498, 34.60279005425693},
		{499, 34.231204914439},
		{500, 34.099389551023904},
		{501, 34.22803109888905},
		{502, 34.610384365507166},
		{503, 34.902573683307146},
		{504, 35.0720672663373},
		{505, 35.02095234082352},
		{506, 35.21029830385259},
		{507, 36.39939489896903},
		{508, 36.49626843650683},
		{509, 36.91759867136517},
		{510, 36.62252163480901},
		{511, 36.637052547917165},
		{512, 37.07289132044249},
		{513, 37.943749079996564},
		{514, 37.31678988480502},
		{515, 37.10207023840552},
		{516, 37.50103188910752},
		{517, 36.711556296699854},
		{518, 36.69985201593515},
		{519, 35.88305508619134},
		{520, 35.819177348929244},
		{521, 35.238662967688704},
		{522, 35.204473848884604},
		{523, 35.73171925218891},
		{524, 37.10654099191614},
		{525, 36.97832117698606},
		{526, 37.88944422270623},
		{527, 37.566765945668905},
		{528, 36.952108419930035},
		{529, 37.16172877345256},
		{530, 36.79432449958657},
		{531, 36.83537718548058},
		{532, 37.241795032269486},
		{533, 36.98172720447497},
		{534, 37.12848852369968},
		{535, 37.144201171899056},
		{536, 37.291084012425635},
		{537, 37.20361280452033},
		{538, 37.14673041600966},
		{539, 36.56539045560211},
		{540, 36.46052858989325},
		{541, 36.577035838031236},
		{542, 36.413434939980604},
		{543, 36.830541819855966},
		{544, 36.708601164617306},
		{545, 36.754028252130254},
		{546, 36.86880281045058},
		{547, 36.20522653559122},
		{548, 36.19016853939169},
		{549, 35.60660078018533},
		{550, 35.58380480655832},
		{551, 36.15574897354542},
		{552, 35.96603587272573},
		{553, 36.01846266557714},
		{554, 36.1246059100681},
		{555, 35.776226062342324},
		{556, 35.53756438274776},
		{557, 36.09285691162272},
		{558, 36.024821241563764},
		{559, 36.07242575850486},
		{560, 36.902047436744915},
		{561, 36.783371618493575},
		{562, 36.97312505169229},
		{563, 38.33987731208528},
		{564, 38.12211125979531},
		{565, 37.867344065570286},
		{566, 37.91294220403035},
		{567, 37.90421561454514},
		{568, 37.52932323225818},
		{569, 38.09065950561944},
		{570, 38.3481668904528},
		{571, 38.38853417076884},
		{572, 38.82875488776441},
		{573, 39.30100206552399},
		{574, 39.22872668781665},
		{575, 39.26377992972712},
		{576, 39.11286987148877},
		{577, 38.55996270262097},
		{578, 39.53759984840164},
		{579, 39.434972831723044},
		{580, 39.58456959406775},
		{581, 40.02469156333131},
		{582, 39.83799518416734},
		{583, 41.066310308184526},
		{584, 41.249674158569356},
		{585, 41.84405324758257},
		{586, 42.44197850928179},
		{587, 42.44435586698777},
		{588, 42.51450858652831},
		{589, 42.497079884180856},
		{590, 41.86201338457368},
		{591, 41.97430910917171},
		{592, 42.38604395890263},
		{593, 42.77701512105045},
		{594, 42.917712727399795},
		{595, 41.92733574585986},
		{596, 41.98001270512809},
		{597, 42.21709441156598},
		{598, 41.73101118068132},
		{599, 41.511566903501254},
		{600, 41.151843749654674},
		{601, 40.936735208747976},
		{602, 41.07670022261416},
		{603, 41.00310883262705},
		{604, 41.175657930592564},
		{605, 39.65057441921113},
		{606, 40.59197307871199},
		{607, 40.19328008308628},
		{608, 39.96642122821799},
		{609, 39.980554983282815},
		{610, 39.198802516126015},
		{611, 40.28881956306739},
		{612, 40.835001630650424},
		{613, 40.96840019049191},
		{614, 41.47803284199829},
		{615, 42.31117692587696},
		{616, 42.56501744522036},
		{617, 40.75017426985965},
		{618, 40.54474737773533},
		{619, 40.32299207284596},
		{620, 40.59233541049153},
		{621, 39.799369403233875},
		{622, 39.90740256156506},
		{623, 39.84656589770128},
		{624, 40.51863738080248},
		{625, 40.36927897222197},
		{626, 39.577466020927666},
		{627, 40.24059624379228},
		{628, 39.888654784809695},
		{629, 39.06459566315487},
		{630, 39.21824625899819},
		{631, 39.707949621228416},
		{632, 39.6862655989382},
		{633, 39.232670266668386},
		{634, 38.72226788949448},
		{635, 38.90143970392931},
		{636, 38.58114412526509},
		{637, 37.47764070721714},
		{638, 38.14287868141234},
		{639, 37.95489640397961},
		{640, 37.978479310316544},
		{641, 38.08870157682401},
		{642, 37.86650279398312},
		{643, 37.83158400391423},
		{644, 37.661339861002425},
		{645, 37.77028468310174},
		{646, 38.19873503550377},
		{647, 37.84181306063926},
		{648, 36.15953352691078},
		{649, 36.15954745676219},
		{650, 36.70039654101666},
		{651, 36.747404928048674},
		{652, 36.45440618086992},
		{653, 36.50375344553345},
		{654, 36.12499971175383},
		{655, 36.25540639161984},
		{656, 36.14128341022631},
		{657, 36.13550126300937},
		{658, 36.47636290489859},
		{659, 36.52934581511136},
		{660, 36.180684191314654},
		{661, 36.1345774586021},
		{662, 35.88734753480093},
		{663, 35.910114094303935},
		{664, 37.494624894014834},
		{665, 37.388322481490356},
		{666, 37.51949607161456},
		{667, 37.42672416426224},
		{668, 37.607431895150505},
		{669, 38.1169043451165},
		{670, 38.198701944392226},
		{671, 37.672228180889036},
		{672, 37.573597996143555},
		{673, 37.61475549631909},
		{674, 37.704351969731974},
		{675, 36.526503465131775},
		{676, 37.14283711760895},
		{677, 37.042216595367044},
		{678, 37.19943347657908},
		{679, 37.030753837557455},
		{680, 37.29832109446188},
		{681, 37.34909191845969},
		{682, 37.396667764315495},
		{683, 37.71513970238973},
		{684, 37.035963822400284},
		{685, 37.09132966834279},
		{686, 36.671363246669195},
		{687, 36.725271547538746},
		{688, 36.732765304609515},
		{689, 37.049756926857675},
		{690, 37.100425916489115},
		{691, 37.80849557841213},
		{692, 38.00370168917147},
		{693, 38.65064301128746},
		{694, 38.16137008804746},
		{695, 38.16628690738749},
		{696, 38.509868983636345},
		{697, 38.51329094834429},
		{698, 38.63409846835321},
		{699, 38.33551139578646},
		{700, 37.86178126970245},
		{701, 37.20625176875522},
		{702, 37.13864013016608},
		{703, 36.598956314019325},
		{704, 36.73225170870823},
		{705, 36.645909925459954},
		{706, 36.931378033672665},
		{707, 37.15159698187774},
		{708, 37.20499450218726},
		{709, 37.312534314076736},
		{710, 38.234122213566266},
		{711, 38.23482019038691},
		{712, 39.50821685803287},
		{713, 39.3687472311753},
		{714, 40.43514365409954},
		{715, 40.44682389295688},
		{716, 39.81067959969004},
		{717, 39.4239320658717},
		{718, 39.54620136509768},
		{719, 39.70807547297041},
		{720, 39.66237013592385},
		{721, 39.72023820319751},
		{722, 40.02829005394066},
		{723, 39.9923106822397},
		{724, 39.88229973919716},
		{725, 39.577778632304906},
		{726, 39.42713453659046},
		{727, 39.43664948339558},
		{728, 39.90314312163109},
		{729, 40.00741574107013},
		{730, 40.7177664595581},
		{731, 40.72045099279074},
		{732, 38.3054003174184},
		{733, 37.63394119070095},
		{734, 37.190128597342806},
		{735, 37.63802392396217},
		{736, 37.09659077679385},
		{737, 37.08430082665866},
		{738, 37.031926029911546},
		{739, 36.92762266554352},
		{740, 36.768283960686276},
		{741, 36.80986118421022},
		{742, 37.00023584840072},
		{743, 37.37757227329164},
		{744, 37.65237108287256},
		{745, 37.65431119266612},
		{746, 37.78202911987313},
		{747, 37.26755576516154},
		{748, 37.253878362362926},
		{749, 37.25181149353707},
		{750, 38.046853987139436},
		{751, 38.52088550994239},
		{752, 38.50060736503108},
		{753, 39.721168829902766},
		{754, 39.714977806533284},
		{755, 41.2027128451164},
		{756, 41.271353835056736},
		{757, 41.42756394972893},
		{758, 41.20791889996719},
		{759, 41.51542890247571},
		{760, 41.533271125006856},
		{761, 41.57431095381387},
		{762, 42.43297879649776},
		{763, 42.697486616671064},
		{764, 42.943817792210965},
		{765, 43.00326844639773},
		{766, 43.04122373477804},
		{767, 42.72385932125831},
		{768, 42.91563938083615},
		{769, 43.09789890970447},
		{770, 43.21939147903337},
		{771, 42.593500985806116},
		{772, 42.552074422506266},
		{773, 41.96625047640962},
		{774, 42.43760021996765},
		{775, 42.15036608724706},
		{776, 42.01801170238841},
		{777, 42.108251206065354},
		{778, 42.13720797898185},
		{779, 41.734510693754125},
		{780, 41.98861197273539},
		{781, 41.855890804590906},
		{782, 41.83653956517087},
		{783, 41.84729249879647},
		{784, 41.34451591903922},
		{785, 41.198937855641844},
		{786, 40.9934126996872},
		{787, 40.33193886547389},
		{788, 40.42177093298795},
		{789, 40.56423832118387},
		{790, 40.56930078212437},
		{791, 40.44001792153413},
		{792, 39.36239492015202},
		{793, 39.2299512438198},
		{794, 39.98930528782557},
		{795, 39.78753261124546},
		{796, 39.7771218730521},
		{797, 40.08078557739916},
		{798, 39.9026881045777},
		{799, 39.846598822934695},
		{800, 39.819165988548605},
		{801, 39.779536346223246},
		{802, 39.417184051357914},
		{803, 39.04248228046798},
		{804, 39.04467471746209},
		{805, 39.19976668706493},
		{806, 38.62608414650186},
		{807, 38.56950606795273},
		{808, 38.11427821927686},
		{809, 38.003564811967195},
		{810, 38.9186775339263},
		{811, 39.32280711240079},
		{812, 39.37066040646152},
		{813, 39.35771550162152},
		{814, 39.82593927687213},
		{815, 39.41511912781052},
		{816, 39.632089125382805},
		{817, 39.7013716770543},
		{818, 39.71871324205181},
		{819, 39.3691037472924},
		{820, 39.4630528375144},
		{821, 39.463557590573124},
		{822, 39.84149848240294},
		{823, 39.731112944493475},
		{824, 39.46553273230596},
		{825, 38.983001317774516},
		{826, 39.111806633972954},
		{827, 39.11241986582127},
		{828, 39.060815486719235},
		{829, 38.62106612409818},
		{830, 38.45726527644363},
		{831, 38.46243114268653},
		{832, 37.81089603641852},
		{833, 37.06489698994548},
		{834, 35.65801215219413},
		{835, 35.598044467413054},
		{836, 35.51269552874315},
		{837, 35.26479970268285},
		{838, 36.55531335895278},
		{839, 36.707855369730034},
		{840, 36.5489032234404},
		{841, 36.3485272462068},
		{842, 36.365162732119266},
		{843, 36.175883792606705},
		{844, 36.16643352096541},
		{845, 36.721302046157795},
		{846, 36.738751647960406},
		{847, 36.499637035175965},
		{848, 36.461882187600125},
		{849, 36.474313661197286},
		{850, 36.138203284641186},
		{851, 36.47458889999187},
		{852, 36.9122685068765},
		{853, 36.84193719836966},
		{854, 36.016869149964144},
		{855, 35.908626743361204},
		{856, 35.853057192524155},
		{857, 35.49400703601318},
		{858, 35.23328368215224},
		{859, 35.43381027728788},
		{860, 35.441912396566295},
		{861, 36.11980562386126},
		{862, 35.987081872648865},
		{863, 35.354742046128464},
		{864, 35.11437170180045},
		{865, 35.10075744627144},
		{866, 35.33061979174065},
		{867, 35.26826901332004},
		{868, 34.76420766370852},
		{869, 34.36825504722903},
		{870, 33.95310090031108},
		{871, 34.76854906618263},
		{872, 34.96941220214851},
		{873, 34.89082477498721},
		{874, 34.930226673548425},
		{875, 34.818344629526955},
		{876, 33.46752591731415},
		{877, 32.4461932776035},
		{878, 32.63093881621515},
		{879, 32.571549274273316},
		{880, 31.70273743751098},
		{881, 31.560570134656707},
		{882, 30.11896242237412},
		{883, 29.976753491813355},
		{884, 30.151470049420453},
		{885, 29.968667652811302},
		{886, 29.914108861900175},
		{887, 29.315297425726456},
		{888, 29.465096537128055},
		{889, 30.38412313034993},
		{890, 30.529005936656326},
		{891, 30.377111661676715},
		{892, 30.690112657456975},
		{893, 31.19665096563887},
		{894, 30.23180166165202},
		{895, 30.214575260830543},
		{896, 30.61887791868095},
		{897, 31.69516453152183},
		{898, 31.724657127738052},
		{899, 31.3260343161325},
		{900, 31.448576476567858},
		{901, 31.384197051367188},
		{902, 31.42382604514501},
		{903, 31.77933470325809},
		{904, 31.54527210384609},
		{905, 31.662859065404803},
		{906, 31.952233276070345},
		{907, 31.710429406503827},
		{908, 31.69910928793987},
		{909, 31.26054806750292},
		{910, 31.252913740901814},
		{911, 31.069356216279907},
		{912, 31.450376052945543},
		{913, 31.446602308578885},
		{914, 32.88848724097737},
		{915, 32.97405474992589},
		{916, 32.95989543002121},
		{917, 33.50228160406862},
		{918, 33.57376811625785},
		{919, 33.49455873288756},
		{920, 32.739675795181945},
		{921, 32.69683391724602},
		{922, 33.81401934792278},
		{923, 33.68504119872676},
		{924, 33.08473835369315},
		{925, 32.71783936639953},
		{926, 33.576629314879405},
		{927, 33.496669377208725},
		{928, 32.32323980202774},
		{929, 32.19540083945545},
		{930, 31.681562294745188},
		{931, 31.21936553988134},
		{932, 32.02350301138198},
		{933, 31.99391696064781},
		{934, 31.222294641434715},
		{935, 31.49393327555392},
		{936, 31.60562877897029},
		{937, 31.719747501964054},
		{938, 31.631337228109494},
		{939, 31.876599195053196},
		{940, 31.839975677295737},
		{941, 31.57998061624259},
		{942, 32.247156373569744},
		{943, 33.13453225404717},
		{944, 33.57148226581986},
		{945, 33.67881606804257},
		{946, 34.27627744671606},
		{947, 34.2667236377486},
		{948, 35.0394972266412},
		{949, 35.06221556029825},
		{950, 35.317831610972426},
		{951, 35.47650956265658},
		{952, 35.92884652798027},
		{953, 36.40171114341679},
		{954, 35.651733034914436},
		{955, 36.021038886103796},
		{956, 36.194620959224366},
		{957, 36.14405991221338},
		{958, 36.02271118328351},
		{959, 36.01617792703485},
		{960, 36.718644368420634},
		{961, 36.658954226071046},
		{962, 36.58675202460727},
		{963, 35.89078679017791},
		{964, 35.94749384377098},
		{965, 35.92838317262612},
		{966, 34.32490064912566},
		{967, 33.68329350874763},
		{968, 33.72780060374807},
		{969, 33.521931400031036},
		{970, 33.48546378484414},
		{971, 33.729671379093105},
		{972, 32.483138764110244},
		{973, 32.70061143845538},
		{974, 31.882058598338592},
		{975, 31.85978103716163},
		{976, 31.360355110091252},
		{977, 31.338506662447838},
		{978, 31.4975196000238},
		{979, 31.636516566035457},
		{980, 31.76928554942759},
		{981, 31.596565826225252},
		{982, 31.24504603522091},
		{983, 30.97685607999551},
		{984, 30.776149614114455},
		{985, 30.369022511891757},
		{986, 30.65823464304316},
		{987, 30.536961423755283},
		{988, 30.543171096017304},
		{989, 29.709033348016842},
		{990, 29.787775153315135},
		{991, 30.020098011459627},
		{992, 30.161570003700696},
		{993, 30.110594653721783},
		{994, 30.269521765071406},
		{995, 30.887702552351005},
		{996, 31.092501292990715},
		{997, 30.96235060201595},
		{998, 31.371052725132344},
		{999, 31.652461552974707},
		{1000, 31.925382030352395},
		{1001, 32.09718279718192},
		{1002, 32.404705995647134},
		{1003, 32.40399854679425},
		{1004, 32.105619052543034},
		{1005, 32.123902211392696},
		{1006, 32.26894930916644},
		{1007, 32.06571185804976},
		{1008, 32.27138533885846},
		{1009, 32.459468377391936},
		{1010, 32.45637104295923},
		{1011, 33.97355416481095},
		{1012, 34.073372443262755},
		{1013, 34.555509854599876},
		{1014, 34.001992433795586},
		{1015, 34.028775375039515},
		{1016, 33.15444517016032},
		{1017, 33.25999551152861},
		{1018, 33.56889630842039},
		{1019, 33.836008073592865},
		{1020, 34.6557254577998},
		{1021, 34.16915786529838},
		{1022, 33.91355886515464},
		{1023, 33.53814944935212},
		{1024, 33.73093246034526},
		{1025, 33.779257221704746},
		{1026, 33.55901656076105},
		{1027, 33.522411543634334},
		{1028, 33.308377022855574},
		{1029, 33.46872487000558},
		{1030, 33.398428332372106},
		{1031, 32.78130678002823},
		{1032, 32.569113758452666},
		{1033, 31.58571790720343},
		{1034, 32.16172427938117},
		{1035, 31.661979621179476},
		{1036, 31.632175065844496},
		{1037, 31.789546741031184},
		{1038, 32.26513372369237},
		{1039, 32.18304328830448},
		{1040, 32.71362639662142},
		{1041, 31.299268596529224},
		{1042, 27.792537058477052},
		{1043, 31.385259077931753},
		{1044, 30.591065858607116},
		{1045, 31.272338876555935},
		{1046, 31.673417165689862},
		{1047, 31.185485416617453},
		{1048, 31.29116101415942},
		{1049, 31.420045699024275},
		{1050, 32.72027856671056},
		{1051, 32.70728464282712},
		{1052, 32.84488754596194},
		{1053, 33.19971370723099},
		{1054, 33.00087402494973},
		{1055, 32.99077340899255},
		{1056, 32.83232129107784},
		{1057, 32.30498262311541},
		{1058, 32.30946094376116},
		{1059, 32.940891339151776},
		{1060, 32.68854192681414},
		{1061, 32.73363409330329},
		{1062, 32.79589758581314},
		{1063, 32.289791532294295},
		{1064, 32.68604720099993},
		{1065, 33.33078243465505},
		{1066, 33.54826648297002},
		{1067, 33.40865566016796},
		{1068, 33.41296471315078},
		{1069, 32.77182145012062},
		{1070, 32.33224727266914},
		{1071, 32.27203157051601},
		{1072, 32.26109905266389},
		{1073, 32.921499096795074},
		{1074, 33.38395175893338},
		{1075, 33.78768855190261},
		{1076, 33.442367223026764},
		{1077, 33.237913854994794},
		{1078, 31.147232293821737},
		{1079, 31.146482126046756},
		{1080, 31.71150780117646},
		{1081, 31.814296312484636},
		{1082, 30.955859429080363},
		{1083, 30.987259649137073},
		{1084, 30.89065910781576},
		{1085, 31.16579586461409},
		{1086, 31.118733218136573},
		{1087, 30.533273297600925},
		{1088, 29.252834071159857},
		{1089, 29.685743434805644},
		{1090, 29.705920523322913},
		{1091, 29.85069842502032},
		{1092, 30.388305038615574},
		{1093, 30.161758590806624},
		{1094, 30.779652282941164},
		{1095, 30.91190072880913},
		{1096, 31.56528710281942},
		{1097, 31.768065818580393},
		{1098, 31.8230334699979},
		{1099, 32.1658225590106},
		{1100, 32.18402247418236},
		{1101, 33.487267406897004},
		{1102, 33.51902089155666},
		{1103, 33.39833431034105},
		{1104, 32.50713483623776},
		{1105, 32.66530621931014},
		{1106, 32.78927126650209},
		{1107, 32.650964726546256},
		{1108, 32.70706148431291},
		{1109, 32.916943844199004},
		{1110, 32.49004088753038},
		{1111, 32.945619481604744},
		{1112, 33.03101393088018},
		{1113, 33.01159487630862},
		{1114, 33.17414749212253},
		{1115, 34.21219988578758},
		{1116, 34.00043238845383},
		{1117, 33.61923485510282},
		{1118, 34.275948039809364},
		{1119, 33.87944072377637},
		{1120, 33.57361872056542},
		{1121, 33.60777850243776},
		{1122, 33.95519829789812},
		{1123, 34.101866130091636},
		{1124, 35.08344176854378},
		{1125, 35.290045657998256},
		{1126, 34.99789523160777},
		{1127, 35.11162512342385},
		{1128, 35.150203027075506},
		{1129, 34.9547553234651},
		{1130, 35.68267560816188},
		{1131, 35.94530333733083},
		{1132, 36.40684420002165},
		{1133, 36.90897436886569},
		{1134, 36.68925056413046},
		{1135, 36.77241779692453},
		{1136, 36.7768373962142},
		{1137, 36.615559524302526},
		{1138, 36.15108571210806},
		{1139, 36.31887166999472},
		{1140, 36.25359696272827},
		{1141, 36.04048635034041},
		{1142, 36.00631287066912},
		{1143, 36.459483786091326},
		{1144, 36.523711914237204},
		{1145, 35.76502964124057},
		{1146, 36.18603634547918},
		{1147, 36.143227345894964},
		{1148, 35.42846972819206},
		{1149, 34.22551552384586},
		{1150, 35.085356710729094},
		{1151, 34.978408345953554},
		{1152, 35.02162912627897},
		{1153, 34.6749544956021},
		{1154, 34.5294083257531},
		{1155, 33.989361791250865},
		{1156, 33.90560409554212},
		{1157, 34.22819180059112},
		{1158, 35.09979866464593},
		{1159, 35.459597394271825},
		{1160, 35.028413870661275},
		{1161, 35.07365163864229},
		{1162, 35.008455674695846},
		{1163, 34.87027987153975},
		{1164, 32.73740982908738},
		{1165, 35.86288920810587},
		{1166, 36.38448730256452},
		{1167, 35.69198792205293},
		{1168, 35.7287802068078},
		{1169, 35.67047911791235},
		{1170, 35.65931562676154},
		{1171, 35.63860255804954},
		{1172, 36.28377914027185},
		{1173, 36.31724433582806},
		{1174, 36.42873315721097},
		{1175, 36.55293797881833},
		{1176, 36.68858364718202},
		{1177, 36.68542383419321},
		{1178, 36.59630640724288},
		{1179, 36.46919978323624},
		{1180, 35.97612499492244},
		{1181, 35.97470028204401},
		{1182, 36.88186754506275},
		{1183, 36.89180762556425},
		{1184, 37.398624973193115},
		{1185, 37.6485574658129},
		{1186, 37.59944793075436},
		{1187, 37.52123044476694},
		{1188, 37.545545238118},
		{1189, 37.63568398432097},
		{1190, 37.60117292673316},
		{1191, 37.76737303107856},
		{1192, 37.796708933792935},
		{1193, 38.44788884052119},
		{1194, 38.433526334130406},
		{1195, 38.53261361058563},
		{1196, 38.20625193191746},
		{1197, 38.216892858955696},
		{1198, 38.10624817074387},
		{1199, 38.31498368822061},
		{1200, 38.28171670233931},
		{1201, 38.03504598890333},
		{1202, 37.469381149070585},
		{1203, 37.645843865994834},
		{1204, 37.996863546861626},
		{1205, 37.39010863231819},
		{1206, 37.916484620097826},
		{1207, 37.9792008265341},
		{1208, 37.56402382212345},
		{1209, 37.64236828858301},
		{1210, 38.20048604682538},
		{1211, 38.1135776386156},
		{1212, 38.06926736333271},
		{1213, 37.85109980183144},
		{1214, 37.8667193253515},
		{1215, 37.79731989239691},
		{1216, 37.79569290509785},
		{1217, 37.507680665850124},
		{1218, 37.86538998455543},
		{1219, 37.97413406343451},
		{1220, 38.153189871670634},
		{1221, 37.705945919911386},
		{1222, 38.003018638410715},
		{1223, 37.97804975659373},
		{1224, 37.86005819640923},
		{1225, 37.74622347438676},
		{1226, 37.24273013769576},
		{1227, 37.471847978186396},
		{1228, 36.574577925568015},
		{1229, 36.898112403986175},
		{1230, 37.93262825928585},
		{1231, 37.98350758652906},
		{1232, 37.3327630080204},
		{1233, 37.87253628352105},
		{1234, 37.03465628886385},
		{1235, 37.3628779234913},
		{1236, 37.257920892232235},
		{1237, 37.355020597223806},
		{1238, 36.42612381389829},
		{1239, 35.71849960760021},
		{1240, 35.569737001180215},
		{1241, 35.639328778372764},
		{1242, 36.67505414760637},
		{1243, 36.529877025906195},
		{1244, 36.17805747298349},
		{1245, 36.20730061152778},
		{1246, 36.7654190000416},
		{1247, 36.066963570873966},
		{1248, 34.80315462413555},
		{1249, 34.79204497446974},
		{1250, 34.96282416930701},
		{1251, 35.29525328571966},
		{1252, 35.39276674967225},
		{1253, 35.17789113339765},
		{1254, 35.1734239698592},
		{1255, 36.27186268761327},
		{1256, 36.12969032844646},
		{1257, 35.56797468172719},
		{1258, 35.413952983479305},
		{1259, 35.473554398381665},
		{1260, 34.959780400150386},
		{1261, 34.705612847987084},
		{1262, 35.122081505219015},
		{1263, 35.54647234411569},
		{1264, 35.56585165590874},
		{1265, 34.07163330273662},
		{1266, 34.061764136955},
		{1267, 34.98718482740182},
		{1268, 35.194478377248124},
		{1269, 34.814779163097306},
		{1270, 35.63339066284622},
		{1271, 36.248018614293784},
		{1272, 35.89931722172987},
		{1273, 36.02707673294714},
		{1274, 35.47928825105021},
		{1275, 35.339226659095814},
		{1276, 36.04365822060287},
		{1277, 36.12975065194946},
		{1278, 35.657328019340454},
		{1279, 35.92456974548614},
		{1280, 36.330656914157935},
		{1281, 36.192088120039486},
		{1282, 35.48734879533039},
		{1283, 35.20967589696835},
		{1284, 35.16528283177774},
		{1285, 35.05450151673027},
		{1286, 34.083660774124404},
		{1287, 33.772468853879964},
		{1288, 33.29191351706884},
		{1289, 33.40417208662001},
		{1290, 32.607679572698984},
		{1291, 32.60800666862871},
		{1292, 32.6060770265256},
		{1293, 32.50260313437235},
		{1294, 32.66708354095242},
		{1295, 32.66682027747426},
		{1296, 33.0078376785496},
		{1297, 32.79448909601},
		{1298, 33.33055451566498},
		{1299, 33.80720872380922},
		{1300, 34.03662018610426},
		{1301, 33.471561770605334},
		{1302, 33.464542278200675},
		{1303, 33.5135192502925},
		{1304, 33.522105679079196},
		{1305, 33.486732091763336},
		{1306, 34.102696294452976},
		{1307, 34.28410402104561},
		{1308, 34.50821094970082},
		{1309, 34.2800121277366},
		{1310, 34.07699583444763},
		{1311, 33.29032898991077},
		{1312, 33.447416548419994},
		{1313, 33.07070289905697},
		{1314, 32.76441433179846},
		{1315, 32.35364095869243},
		{1316, 32.19453136744108},
		{1317, 32.001227569765504},
		{1318, 32.1893553685659},
		{1319, 32.17192961357054},
		{1320, 32.05156175088731},
		{1321, 32.01319521995405},
		{1322, 31.361540797597904},
		{1323, 31.358737048716332},
		{1324, 31.4094163556713},
		{1325, 31.385674150907523},
		{1326, 30.397821572277874},
		{1327, 30.430993318308072},
		{1328, 30.559151734617863},
		{1329, 30.709052945784077},
		{1330, 30.762480629193092},
		{1331, 30.428823245671445},
		{1332, 30.549369360601233},
		{1333, 30.401524153538364},
		{1334, 30.862514784963658},
		{1335, 30.543179751483258},
		{1336, 30.546876105280212},
		{1337, 30.8118556608746},
		{1338, 30.73308277586123},
		{1339, 31.09586849152352},
		{1340, 30.443543543528172},
		{1341, 30.574438626388865},
		{1342, 30.433112514559557},
		{1343, 29.60468065056554},
		{1344, 29.518027759834045},
		{1345, 29.530716732475156},
		{1346, 29.258574444161773},
		{1347, 28.96213974116116},
		{1348, 30.094589411608464},
		{1349, 30.027880530088794},
		{1350, 30.00173657659883},
		{1351, 30.7570211333231},
		{1352, 30.905455874138642},
		{1353, 30.95776014140416},
		{1354, 31.25924961163502},
		{1355, 31.28781614068638},
		{1356, 31.259224092967646},
		{1357, 31.471490532081248},
		{1358, 30.66993696457886},
		{1359, 29.51601931381402},
		{1360, 29.658359527955362},
		{1361, 29.498776144228817},
		{1362, 29.0952884352307},
		{1363, 27.583844233928247},
		{1364, 27.104268459905846},
		{1365, 25.95144210780829},
		{1366, 25.823464503416666},
		{1367, 25.72514162857761},
		{1368, 25.654123815674225},
		{1369, 26.051979147188657},
		{1370, 25.841597348616787},
		{1371, 25.03088000259754},
		{1372, 24.40430526113091},
		{1373, 24.39450861715055},
		{1374, 24.868258110961357},
		{1375, 24.87891945990089},
		{1376, 24.826829203959203},
		{1377, 24.723127466527284},
		{1378, 25.189101108151846},
		{1379, 24.999892026613335},
		{1380, 25.403952465657824},
		{1381, 25.395818912419763},
		{1382, 25.361488701260853},
		{1383, 25.168837708367573},
		{1384, 25.822974064286573},
		{1385, 25.184633998151693},
		{1386, 25.673392593447062},
		{1387, 25.493115319468433},
		{1388, 25.616885562952366},
		{1389, 26.26185502334556},
		{1390, 26.63671721716633},
		{1391, 27.41659614028529},
		{1392, 27.180001027499763},
		{1393, 27.31191586358311},
		{1394, 27.41516507193562},
		{1395, 27.621542573182392},
		{1396, 28.333329103903207},
		{1397, 28.490364050694232},
		{1398, 28.282737229661876},
		{1399, 28.487368411327616},
		{1400, 27.619991904229085},
		{1401, 27.775228746290942},
		{1402, 27.75784788858771},
		{1403, 26.388008503362745},
		{1404, 26.390446759456594},
		{1405, 26.804841863728445},
		{1406, 26.645161583486924},
		{1407, 25.978560150820044},
		{1408, 25.928009125329705},
		{1409, 25.928237301882948},
		{1410, 25.750677096758384},
		{1411, 25.3386270250864},
		{1412, 25.140774560316675},
		{1413, 24.34074260607449},
		{1414, 24.754961425981048},
		{1415, 24.730194413283783},
		{1416, 24.920450795877183},
		{1417, 25.024801997124456},
		{1418, 24.6651943693905},
		{1419, 25.194960339720506},
		{1420, 25.34229435510204},
		{1421, 25.305380825552025},
		{1422, 25.412841036914795},
		{1423, 25.505668659821385},
		{1424, 25.930434241278466},
		{1425, 25.958267633145237},
		{1426, 26.031451433938873},
		{1427, 26.586990196306772},
		{1428, 27.292096678546},
		{1429, 28.12071488383503},
		{1430, 28.02832144500101},
		{1431, 28.58386148422691},
		{1432, 28.79404266374261},
		{1433, 29.738295917981866},
		{1434, 29.720007389392677},
		{1435, 29.63633778940114},
		{1436, 29.68841036823205},
		{1437, 29.575033122960512},
		{1438, 29.539149897548384},
		{1439, 29.80686249903287},
		{1440, 30.862182502538953},
		{1441, 30.42493141449586},
		{1442, 30.427703473898646},
		{1443, 30.502760352966796},
		{1444, 30.537509584235174},
		{1445, 30.206448675310977},
		{1446, 30.230172108384416},
		{1447, 30.164364772985248},
		{1448, 29.417259389108583},
		{1449, 29.280495127154293},
		{1450, 29.331776246449813},
		{1451, 28.98662862990845},
		{1452, 29.752510306571484},
		{1453, 29.70066010243845},
		{1454, 29.357272975382973},
		{1455, 29.25016590767666},
		{1456, 29.355245117563307},
		{1457, 29.533981898101043},
		{1458, 29.569017902727573},
		{1459, 29.611976373457114},
		{1460, 29.731805290138638},
		{1461, 29.757994213197602},
		{1462, 30.0901622202274},
		{1463, 31.279393484956277},
		{1464, 31.228915684424805},
		{1465, 31.39987446802975},
		{1466, 30.81523244839042},
		{1467, 31.19319811379786},
		{1468, 31.21869066135987},
		{1469, 31.378064726660238},
		{1470, 31.36503448737635},
		{1471, 30.890723656435668},
		{1472, 31.278271018448063},
		{1473, 31.27351266944355},
		{1474, 30.906433524045895},
		{1475, 31.094199381637562},
		{1476, 32.22446329349785},
		{1477, 31.755676495678124},
		{1478, 31.863329580086756},
		{1479, 34.1769485077606},
		{1480, 33.67109006952487},
		{1481, 34.032560599893785},
		{1482, 35.17463593455005},
		{1483, 34.68680491085987},
		{1484, 35.34323186904023},
		{1485, 36.06846197316916},
		{1486, 35.75474567916718},
		{1487, 34.95879681397107},
		{1488, 34.91513272089497},
		{1489, 34.27429545432343},
		{1490, 34.47677587538645},
		{1491, 34.8837191993053},
		{1492, 34.888682229883216},
		{1493, 34.6615444728743},
		{1494, 34.691697874937915},
		{1495, 34.673137205747096},
		{1496, 34.619588001105676},
		{1497, 34.67924802646811},
		{1498, 34.711467226688804},
		{1499, 34.378496298766606},
		{1500, 34.01906505065623},
		{1501, 34.1921149855785},
		{1502, 34.645939695035565},
		{1503, 34.55325778595661},
		{1504, 34.837013970080854},
		{1505, 34.3201819146262},
		{1506, 34.21433963893517},
		{1507, 34.209807913410046},
		{1508, 34.29503290261106},
		{1509, 34.372533557964495},
		{1510, 34.29249674028179},
		{1511, 34.1793952178106},
		{1512, 34.23027204162766},
		{1513, 34.30024655177506},
		{1514, 34.29076290991813},
		{1515, 34.872527881393644},
		{1516, 34.88183138613434},
		{1517, 34.99793065640857},
		{1518, 35.116718830483286},
		{1519, 35.11046533465197},
		{1520, 36.014438556584366},
		{1521, 36.02360905142489},
		{1522, 35.91482043384545},
		{1523, 35.809274512011065},
		{1524, 35.59619773000511},
		{1525, 35.44019543122139},
		{1526, 35.64144780604629},
		{1527, 35.58080982359661},
		{1528, 35.452624932745614},
		{1529, 35.467238834711935},
		{1530, 35.041073967062886},
		{1531, 34.27022167037798},
		{1532, 33.77867219668047},
		{1533, 33.675446148880425},
		{1534, 34.29649579312852},
		{1535, 33.80063094230085},
		{1536, 33.83706673096555},
		{1537, 34.19813699318839},
		{1538, 34.67898341154741},
		{1539, 34.61565170828406},
		{1540, 34.88435222539337},
		{1541, 34.74803849982474},
		{1542, 34.88836986733776},
		{1543, 34.316664346866176},
		{1544, 35.1429379016867},
		{1545, 35.236518386423754},
		{1546, 35.480022507695814},
		{1547, 35.51129848892317},
		{1548, 35.55074228557621},
		{1549, 35.47965462275921},
		{1550, 35.1614123321548},
		{1551, 34.649935916461956},
		{1552, 33.831408529297455},
		{1553, 33.68659149830347},
		{1554, 34.76348070802675},
		{1555, 34.75436175642519},
		{1556, 34.670519236256325},
		{1557, 34.40743801250581},
		{1558, 35.03821600965653},
		{1559, 35.074059881857586},
		{1560, 34.66313179952048},
		{1561, 34.05122520128333},
		{1562, 34.369261269504776},
		{1563, 34.306862410511414},
		{1564, 34.35513437341248},
		{1565, 34.42016699549108},
		{1566, 34.32411882750936},
		{1567, 35.10444315366103},
		{1568, 35.21667415434252},
		{1569, 34.56235394065422},
		{1570, 34.99569538327316},
		{1571, 35.051462529787685},
		{1572, 35.65901988130965},
		{1573, 35.30919470315533},
		{1574, 35.43427648307305},
		{1575, 35.26105873637407},
		{1576, 34.984210066219426},
		{1577, 34.974915529232504},
		{1578, 34.64250053081252},
		{1579, 34.855051142104344},
		{1580, 34.61935447447808},
		{1581, 33.30095950674964},
		{1582, 33.52159175029287},
		{1583, 33.30245847520868},
		{1584, 33.22017010546928},
		{1585, 33.302509858225584},
		{1586, 33.37904181575153},
		{1587, 33.25298440074963},
		{1588, 33.25372890621039},
		{1589, 33.55633290212615},
		{1590, 33.564240306946566},
		{1591, 33.77554531353173},
		{1592, 33.77747427631988},
		{1593, 33.758375775192526},
		{1594, 34.36417258641864},
		{1595, 34.31644882079321},
		{1596, 33.55182639869085},
		{1597, 33.56219047110169},
		{1598, 33.44110230199712},
		{1599, 33.37853776463871},
		{1600, 32.03520633056414},
		{1601, 32.091659309762015},
		{1602, 32.3728274207352},
		{1603, 32.32296532348558},
		{1604, 32.248876392188286},
		{1605, 32.2486900311155},
		{1606, 32.30827587355294},
		{1607, 31.55600150552031},
		{1608, 32.275031428073206},
		{1609, 32.27879842764017},
		{1610, 32.12685506952653},
		{1611, 32.04232751622579},
		{1612, 32.3717511617595},
		{1613, 32.90499426727991},
		{1614, 31.34160341506861},
		{1615, 32.79935984939758},
		{1616, 33.3133749284244},
		{1617, 33.330066949919654},
		{1618, 33.6696207424472},
		{1619, 33.44727416894953},
		{1620, 32.937035354917406},
		{1621, 32.42098193976603},
		{1622, 32.40919020921572},
		{1623, 32.40926615430823},
		{1624, 31.91939496950345},
		{1625, 31.745665996112034},
		{1626, 31.762245569926346},
		{1627, 31.76510278674478},
		{1628, 32.18895805255132},
		{1629, 32.17884231058142},
		{1630, 31.634810462741328},
		{1631, 31.569967535436145},
		{1632, 32.29578832893024},
		{1633, 32.930732352651475},
		{1634, 33.03934988366926},
		{1635, 33.21635409643862},
		{1636, 33.261326384884754},
		{1637, 33.39655980314689},
		{1638, 35.11945078307172},
		{1639, 35.076572468626274},
		{1640, 34.95856618844892},
		{1641, 34.85019550097897},
		{1642, 34.70787112679453},
		{1643, 34.64396731467868},
		{1644, 34.03523254807719},
		{1645, 34.599545249438016},
		{1646, 34.911136115744284},
		{1647, 35.12923123083873},
		{1648, 34.19771898956377},
		{1649, 34.081163717338875},
		{1650, 33.952021163589286},
		{1651, 34.03909563960654},
		{1652, 33.826004075423334},
		{1653, 33.69501183562262},
		{1654, 33.54101912632574},
		{1655, 33.534398838396605},
		{1656, 33.551479085175345},
		{1657, 34.17014679283176},
		{1658, 33.68298225679782},
		{1659, 33.914956135823154},
		{1660, 33.85350696847641},
		{1661, 33.5930418617416},
		{1662, 33.698585740003914},
		{1663, 33.53164709646962},
		{1664, 32.942749249597995},
		{1665, 32.78927293361512},
		{1666, 32.805622975726415},
		{1667, 32.678834731539396},
		{1668, 32.49005865138826},
		{1669, 32.45598674269622},
		{1670, 32.38305018611963},
		{1671, 32.39849660167694},
		{1672, 33.26082532734355},
		{1673, 33.32014170105489},
		{1674, 33.73004210039798},
		{1675, 33.724298776862106},
		{1676, 33.68423539254731},
		{1677, 33.563159682253556},
		{1678, 33.46610598060115},
		{1679, 33.46576401188156},
		{1680, 33.6082093792797},
		{1681, 34.06829829976045},
		{1682, 33.78773476628623},
		{1683, 33.847057378024175},
		{1684, 35.250271418221374},
		{1685, 35.09767253763393},
		{1686, 35.074861457363895},
		{1687, 35.40140497372611},
		{1688, 36.31807881704327},
		{1689, 37.93153971576717},
		{1690, 37.96917757654617},
		{1691, 38.22198787034048},
		{1692, 38.23678368537367},
		{1693, 38.20599590804662},
		{1694, 38.68369317469104},
		{1695, 38.79215511609461},
		{1696, 38.802109502845106},
		{1697, 38.753495704229714},
		{1698, 38.96421874631208},
		{1699, 38.90821233250077},
		{1700, 39.16182425119748},
		{1701, 38.853831057337715},
		{1702, 38.63611099293661},
		{1703, 38.24474852988975},
		{1704, 38.38469009174058},
		{1705, 38.32872094403988},
		{1706, 38.153737338484326},
		{1707, 38.264923332806745},
		{1708, 38.280563758044565},
		{1709, 38.18750466726223},
		{1710, 38.56983066481024},
		{1711, 39.505085657555355},
		{1712, 39.69872974322229},
		{1713, 40.39204144577866},
		{1714, 40.48553785053598},
		{1715, 41.3269897150344},
		{1716, 41.609581527655735},
		{1717, 41.65892696057186},
		{1718, 41.837313217148804},
		{1719, 41.8289668854985},
		{1720, 42.15881862704277},
		{1721, 42.73710053588433},
		{1722, 42.348456207492845},
		{1723, 42.096157824123665},
		{1724, 41.92253556951924},
		{1725, 41.917137854036646},
		{1726, 41.97608613143687},
		{1727, 41.72574431293022},
		{1728, 41.24861627279633},
		{1729, 41.87472943187815},
		{1730, 41.87568170648001},
		{1731, 42.17909911414902},
		{1732, 42.049177661936255},
		{1733, 41.97474828244962},
		{1734, 41.356541003497355},
		{1735, 41.22195929777421},
		{1736, 41.194030410051106},
		{1737, 41.392479793475935},
		{1738, 41.34843546848941},
		{1739, 41.34402528705148},
		{1740, 42.07661962525981},
		{1741, 41.52647896910617},
		{1742, 41.44561097861686},
		{1743, 40.958470191837534},
		{1744, 41.037829903821645},
		{1745, 41.07205195864329},
		{1746, 41.46906637533652},
		{1747, 41.49343224957735},
		{1748, 40.610182804195105},
		{1749, 41.017801824810185},
		{1750, 40.79059366319508},
		{1751, 40.70441966049171},
		{1752, 40.70503981535662},
		{1753, 39.93683574905368},
		{1754, 39.752239396736506},
		{1755, 39.7645522699645},
		{1756, 39.55588740392734},
		{1757, 39.74727156272358},
		{1758, 39.9737782466988},
		{1759, 40.39693575020464},
		{1760, 40.216674372755165},
		{1761, 40.25136763580497},
		{1762, 39.38556407545778},
		{1763, 39.26119592497736},
		{1764, 39.16195286452751},
		{1765, 38.86948923485995},
		{1766, 39.61600974311452},
		{1767, 39.39522112770508},
		{1768, 39.514089866690526},
		{1769, 39.45799756858736},
		{1770, 38.90570527579156},
		{1771, 38.80478381534035},
		{1772, 38.83322167157176},
		{1773, 39.64297039815119},
		{1774, 40.33223301684341},
		{1775, 40.41694728495109},
		{1776, 40.06020383799442},
		{1777, 40.07361881200165},
		{1778, 39.77916448556436},
		{1779, 39.96893684870016},
		{1780, 40.57894081959218},
		{1781, 39.89797496618613},
		{1782, 39.35261558123242},
		{1783, 39.36008989987693},
		{1784, 38.0512977550727},
		{1785, 38.264000581925124},
		{1786, 38.26169623365976},
		{1787, 39.10252385765842},
		{1788, 39.27088966509622},
		{1789, 39.15216453676914},
		{1790, 39.41049327702329},
		{1791, 39.39907719439436},
		{1792, 38.82328669157878},
		{1793, 39.35804609496024},
		{1794, 39.52870877903105},
		{1795, 40.562208982859616},
		{1796, 41.015089776340226},
		{1797, 40.87083252184389},
		{1798, 40.53994999420047},
		{1799, 41.02575733506004},
		{1800, 41.17619373256442},
		{1801, 41.19685023564847},
		{1802, 40.98189573065346},
		{1803, 41.159763360041595},
		{1804, 41.59421552557119},
		{1805, 41.20806640088285},
		{1806, 40.414699831836835},
		{1807, 39.92415966374783},
		{1808, 39.62606546104271},
		{1809, 39.857180263975444},
		{1810, 39.59080107893363},
		{1811, 39.6974862276464},
		{1812, 39.442229052918876},
		{1813, 39.30199180817845},
		{1814, 39.48025720867229},
		{1815, 39.5287187420122},
		{1816, 38.853563440015805},
		{1817, 38.77749075357144},
		{1818, 39.12960232658636},
		{1819, 39.07838534119988},
		{1820, 39.149292277699324},
		{1821, 39.00774814154133},
		{1822, 38.63589451271645},
		{1823, 38.95501568270912},
		{1824, 38.4982817921926},
		{1825, 39.10088500152322},
		{1826, 39.59621160868451},
		{1827, 39.45833354062081},
		{1828, 39.59936421761144},
		{1829, 39.57053924615646},
		{1830, 39.55660528183884},
		{1831, 39.71569674116191},
		{1832, 39.71328630121623},
		{1833, 39.5500745849456},
		{1834, 39.52081122302288},
		{1835, 38.74032920127892},
		{1836, 39.19864530117539},
		{1837, 39.06947571924525},
		{1838, 39.34422885689023},
		{1839, 39.6353362225693},
		{1840, 40.71459696346432},
		{1841, 40.66496952468566},
		{1842, 41.006778236777826},
		{1843, 40.98904213311685},
		{1844, 40.108733704463795},
		{1845, 39.422159369592656},
		{1846, 39.23842350070322},
		{1847, 37.531170184849564},
		{1848, 38.05353522108415},
		{1849, 38.31111320664359},
		{1850, 38.64900610422957},
		{1851, 38.686484249347565},
		{1852, 38.68434197825875},
		{1853, 38.72332458907287},
		{1854, 38.81119764084882},
		{1855, 38.46493433585336},
		{1856, 38.51556317974943},
		{1857, 38.764010535750494},
		{1858, 38.55294929767745},
		{1859, 38.078366113942565},
		{1860, 38.42988961361437},
		{1861, 39.047014068329304},
		{1862, 39.532635843081685},
		{1863, 39.10571993423328},
		{1864, 39.60131420080908},
		{1865, 38.81680138357229},
		{1866, 39.25082176080607},
		{1867, 38.15677220409511},
		{1868, 38.62555210254061},
		{1869, 38.47132788365266},
		{1870, 38.487714681626166},
		{1871, 38.39888830728324},
		{1872, 37.54975105530615},
		{1873, 36.620496899833185},
		{1874, 36.76592939311881},
		{1875, 36.77417927197788},
		{1876, 36.78457313190018},
		{1877, 36.726556157401774},
		{1878, 37.19484339680942},
		{1879, 37.12075085414386},
		{1880, 36.977258419880144},
		{1881, 36.91078025788851},
		{1882, 37.02130072401423},
		{1883, 36.55535121811925},
		{1884, 35.989467257305485},
		{1885, 35.963032268137205},
		{1886, 36.010752822606925},
		{1887, 36.02787704722448},
		{1888, 36.49326570398064},
		{1889, 36.23934542841747},
		{1890, 35.87776015328743},
		{1891, 35.09797528518658},
		{1892, 35.077065290325194},
		{1893, 35.311414001953885},
		{1894, 34.57305509209034},
		{1895, 34.6842074805997},
		{1896, 34.80183031401632},
		{1897, 35.47101264307737},
		{1898, 35.17048394585489},
		{1899, 35.089175368832215},
		{1900, 35.22509160122155},
		{1901, 35.01261679236839},
		{1902, 35.20621635881338},
		{1903, 35.37294264170206},
		{1904, 34.459027714667855},
		{1905, 35.092154761591416},
		{1906, 34.8517351148361},
		{1907, 34.86550272062247},
		{1908, 35.125600870401854},
		{1909, 34.83446288221645},
		{1910, 34.78242112077965},
		{1911, 34.31203602602105},
		{1912, 34.279540168694986},
		{1913, 35.1096803630126},
		{1914, 34.514233849300744},
		{1915, 34.53539867779291},
		{1916, 34.279414052434674},
		{1917, 34.36455267465703},
		{1918, 34.10174900420402},
		{1919, 34.41175163800032},
		{1920, 34.291999205288036},
		{1921, 34.19594013042914},
		{1922, 34.18838364564101},
		{1923, 36.07392483120914},
		{1924, 36.05098431555323},
		{1925, 36.76095964181586},
		{1926, 37.82863560027054},
		{1927, 37.52980493319014},
		{1928, 37.53527503569141},
		{1929, 37.512668716830554},
		{1930, 37.11106227609642},
		{1931, 37.349978643969806},
		{1932, 37.20979207398837},
		{1933, 37.29059943130983},
		{1934, 37.12675552575493},
		{1935, 37.34021255585861},
		{1936, 37.33863802694112},
		{1937, 36.93793225844994},
		{1938, 36.96147855185145},
		{1939, 37.079544775050316},
		{1940, 36.96800493367608},
		{1941, 36.62130515314802},
		{1942, 36.64654224799271},
		{1943, 36.564393168165026},
		{1944, 36.76798510268848},
		{1945, 36.34484500467934},
		{1946, 35.77622429269998},
		{1947, 36.28861461359311},
		{1948, 35.62308019530623},
		{1949, 35.44131748549641},
		{1950, 34.85392909768805},
		{1951, 34.55133668610086},
		{1952, 35.092025906373635},
		{1953, 34.768122961192404},
		{1954, 35.02372314142307},
		{1955, 35.11384033534372},
		{1956, 35.09859916781124},
		{1957, 35.63073140705392},
		{1958, 35.47556248383545},
		{1959, 34.87826460124942},
		{1960, 34.87959003890974},
		{1961, 34.025365090862095},
		{1962, 33.804380004654575},
		{1963, 32.78020946544929},
		{1964, 32.75918431846117},
		{1965, 32.75851314921747},
		{1966, 32.93198375479733},
		{1967, 35.25828074460553},
		{1968, 34.28240693566641},
		{1969, 34.339864432373425},
		{1970, 34.12397376413126},
		{1971, 34.79011341612875},
		{1972, 34.64686103755323},
		{1973, 34.599313028973235},
		{1974, 34.53242934134927},
		{1975, 34.606548457455425},
		{1976, 34.83272344102554},
		{1977, 34.49913157098365},
		{1978, 34.70437557256804},
		{1979, 35.19565588926615},
		{1980, 35.185492244262484},
		{1981, 33.550787666460536},
		{1982, 34.02484580154227},
		{1983, 34.15044793215261},
		{1984, 34.543313702949256},
		{1985, 34.49383893491851},
		{1986, 34.69468439935647},
		{1987, 34.36140916945972},
		{1988, 33.199535764838636},
		{1989, 33.54089185371181},
		{1990, 33.25543526295492},
		{1991, 33.126250139798344},
		{1992, 32.1006804695537},
		{1993, 32.11793625750763},
		{1994, 31.547141310894098},
		{1995, 31.358848538734513},
		{1996, 30.96324192071878},
		{1997, 31.081433577858583},
		{1998, 31.004611604459708},
		{1999, 30.86284767543519},
		{2000, 30.105433307161203},
		{2001, 29.32024170286219},
		{2002, 29.319658236582814},
		{2003, 29.758958255855212},
		{2004, 30.117663632341145},
		{2005, 29.548890824528907},
		{2006, 29.35044585015188},
		{2007, 29.38762759040267},
		{2008, 29.391950686507506},
		{2009, 30.353380249710128},
		{2010, 29.46899984490753},
		{2011, 29.33586115695675},
		{2012, 29.36114381531963},
		{2013, 29.256022938524392},
		{2014, 29.207874497314503},
		{2015, 29.266115045795534},
		{2016, 29.11037246533442},
		{2017, 29.98833975350206},
		{2018, 29.827356428113166},
		{2019, 29.196369679790173},
		{2020, 29.09133736287457},
		{2021, 29.35398305475309},
		{2022, 29.54604416792868},
		{2023, 28.36216318117799},
		{2024, 28.172545798424313},
		{2025, 29.167896346989487},
		{2026, 29.134747648857985},
		{2027, 28.0133642954549},
		{2028, 27.97694686027503},
		{2029, 28.374194072568063},
		{2030, 28.37095153088029},
		{2031, 28.388216858848796},
		{2032, 27.992329533869835},
		{2033, 27.367870148995426},
		{2034, 27.251995482961384},
		{2035, 27.746729670664767},
		{2036, 27.679330290354688},
		{2037, 28.028729073068334},
		{2038, 28.028705243794963},
		{2039, 28.350786367009555},
		{2040, 28.352026432670012},
		{2041, 28.225867429505602},
		{2042, 28.211139910084785},
		{2043, 28.126532263542863},
		{2044, 28.0111605756859},
		{2045, 28.037986830307158},
		{2046, 27.771048205304385},
		{2047, 28.101282898505325},
		{2048, 27.956754355558264},
		{2049, 28.898451768426284},
		{2050, 28.33803560429799},
		{2051, 28.51219696371789},
		{2052, 28.687032331939648},
		{2053, 28.519256261795114},
		{2054, 28.534411822889545},
		{2055, 28.475878463300383},
		{2056, 28.425823720753847},
		{2057, 28.531458363352172},
		{2058, 28.371986321151727},
		{2059, 27.281010674258564},
		{2060, 27.285423846392753},
		{2061, 26.982970399775176},
		{2062, 26.779917891194174},
		{2063, 27.334018434853117},
		{2064, 27.261844645356348},
		{2065, 27.08643958372844},
		{2066, 27.399456700893154},
		{2067, 27.35064731231653},
		{2068, 27.27964623953228},
		{2069, 27.594268915970815},
		{2070, 27.529530803142432},
		{2071, 27.57032488737316},
		{2072, 27.4481123592095},
		{2073, 26.840190037017013},
		{2074, 25.848284039508844},
		{2075, 27.842568040851305},
		{2076, 28.053732543316965},
		{2077, 28.626766043264496},
		{2078, 28.147220846160913},
		{2079, 28.116929624170805},
		{2080, 28.006707726319842},
		{2081, 28.30104291864807},
		{2082, 28.33894272086177},
		{2083, 28.44881078446907},
		{2084, 28.407665090419357},
		{2085, 29.120266868128827},
		{2086, 29.3317588176526},
		{2087, 29.665040474972592},
		{2088, 29.513552545038365},
		{2089, 29.692597123031344},
		{2090, 28.981378296214995},
		{2091, 29.09551924330645},
		{2092, 29.103036068928503},
		{2093, 29.546315663547908},
		{2094, 29.957633494290146},
		{2095, 29.904489752089027},
		{2096, 29.905243264397946},
		{2097, 29.046115152161175},
		{2098, 29.044952829872138},
		{2099, 29.266240445467794},
		{2100, 29.59245009354912},
		{2101, 29.711595098413557},
		{2102, 30.01909364831503},
		{2103, 30.02844709237877},
		{2104, 29.95602684268363},
		{2105, 29.966649831798698},
		{2106, 29.870132199150568},
		{2107, 30.054469107153587},
		{2108, 30.00047327238945},
		{2109, 29.56478041606059},
		{2110, 29.90146475387948},
		{2111, 29.622907648647697},
		{2112, 30.309630232664347},
		{2113, 29.964474309001496},
		{2114, 29.49100419801057},
		{2115, 29.961421989896223},
		{2116, 30.346134915473066},
		{2117, 30.604426349400814},
		{2118, 31.112159919665434},
		{2119, 31.422724201504558},
		{2120, 31.585365400843976},
		{2121, 31.996984724582912},
		{2122, 32.01819220164321},
		{2123, 29.835521461379106},
		{2124, 30.096046165850005},
		{2125, 30.103782504040677},
		{2126, 30.053631787942646},
		{2127, 29.906750519100672},
		{2128, 29.906138940448397},
		{2129, 29.852649788445774},
		{2130, 30.207615016068207},
		{2131, 30.820165055355577},
		{2132, 30.66806843164003},
		{2133, 29.933937853455785},
		{2134, 29.836930249713454},
		{2135, 29.643987595361455},
		{2136, 30.19074784312923},
		{2137, 30.22542736675569},
		{2138, 29.853735660522815},
		{2139, 29.84557151500528},
		{2140, 29.839193019325773},
		{2141, 31.156302724258683
Download .txt
gitextract_wz3_b8r2/

├── .github/
│   ├── CODEOWNERS
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── feature_request.md
│   │   └── question.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── CHANGELOG
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── attack.go
├── attack_nonwindows.go
├── attack_test.go
├── attack_windows.go
├── dump.go
├── encode.go
├── file.go
├── flags.go
├── go.mod
├── go.sum
├── internal/
│   ├── cmd/
│   │   ├── echosrv/
│   │   │   └── main.go
│   │   └── jsonschema/
│   │       └── main.go
│   └── resolver/
│       ├── resolver.go
│       └── resolver_test.go
├── lib/
│   ├── attack.go
│   ├── attack_fuzz.go
│   ├── attack_test.go
│   ├── histogram.go
│   ├── histogram_test.go
│   ├── lttb/
│   │   ├── lttb.go
│   │   └── lttb_test.go
│   ├── metrics.go
│   ├── metrics_test.go
│   ├── pacer.go
│   ├── pacer_test.go
│   ├── plot/
│   │   ├── assets/
│   │   │   ├── VERSIONS
│   │   │   ├── plot.html.tpl
│   │   │   └── uplot-plugins.js
│   │   ├── assets.go
│   │   ├── embed.go
│   │   ├── plot.go
│   │   ├── plot_test.go
│   │   ├── testdata/
│   │   │   └── TestPlot.golden.html
│   │   └── timeseries.go
│   ├── prom/
│   │   ├── grafana.json
│   │   ├── prom.go
│   │   └── prom_test.go
│   ├── reporters.go
│   ├── results.go
│   ├── results_easyjson.go
│   ├── results_fuzz.go
│   ├── results_test.go
│   ├── target.schema.json
│   ├── targets.go
│   ├── targets_easyjson.go
│   ├── targets_fuzz.go
│   ├── targets_test.go
│   └── util_fuzz.go
├── main.go
├── plot.go
├── report.go
├── report_nonwindows.go
├── report_windows.go
└── scripts/
    └── load-ramping/
        ├── README.md
        ├── ramp-requests.plt
        └── ramp-requests.py
Download .txt
SYMBOL INDEX (354 symbols across 45 files)

FILE: attack.go
  function attackCmd (line 24) | func attackCmd() command {
  type attackOpts (line 80) | type attackOpts struct
  function attack (line 117) | func attack(opts *attackOpts) (err error) {
  function processAttack (line 235) | func processAttack(
  function tlsConfig (line 266) | func tlsConfig(insecure bool, certf, keyf string, rootCerts []string) (*...

FILE: attack_nonwindows.go
  function systemSpecificFlags (line 8) | func systemSpecificFlags(fs *flag.FlagSet, opts *attackOpts) {

FILE: attack_test.go
  function TestHeadersSet (line 18) | func TestHeadersSet(t *testing.T) {
  function decodeMetrics (line 39) | func decodeMetrics(buf bytes.Buffer) (vegeta.Metrics, error) {
  function TestAttackSignalOnce (line 58) | func TestAttackSignalOnce(t *testing.T) {
  function TestAttackSignalTwice (line 116) | func TestAttackSignalTwice(t *testing.T) {

FILE: attack_windows.go
  function systemSpecificFlags (line 5) | func systemSpecificFlags(fs *flag.FlagSet, opts *attackOpts) {}

FILE: dump.go
  function dumpCmd (line 7) | func dumpCmd() command {

FILE: encode.go
  constant encodingCSV (line 15) | encodingCSV  = "csv"
  constant encodingGob (line 16) | encodingGob  = "gob"
  constant encodingJSON (line 17) | encodingJSON = "json"
  constant encodeUsage (line 20) | encodeUsage = `Usage: vegeta encode [options] [<file>...]
  function encodeCmd (line 55) | func encodeCmd() command {
  function encode (line 75) | func encode(files []string, to, output string) error {

FILE: file.go
  function file (line 13) | func file(name string, create bool) (*os.File, error) {
  function decoder (line 27) | func decoder(files []string) (vegeta.Decoder, io.Closer, error) {
  type multiCloser (line 47) | type multiCloser
    method Close (line 49) | func (mc multiCloser) Close() error {

FILE: flags.go
  type headers (line 22) | type headers struct
    method String (line 24) | func (h headers) String() string {
    method Set (line 33) | func (h headers) Set(value string) error {
  type localAddr (line 50) | type localAddr struct
    method Set (line 52) | func (ip *localAddr) Set(value string) (err error) {
  type csl (line 58) | type csl
    method Set (line 60) | func (l *csl) Set(v string) error {
    method String (line 65) | func (l csl) String() string { return strings.Join(l, ",") }
  type rateFlag (line 67) | type rateFlag struct
    method Set (line 69) | func (f *rateFlag) Set(v string) (err error) {
    method String (line 100) | func (f *rateFlag) String() string {
  type maxBodyFlag (line 107) | type maxBodyFlag struct
    method Set (line 109) | func (f *maxBodyFlag) Set(v string) (err error) {
    method String (line 128) | func (f *maxBodyFlag) String() string {
  type dnsTTLFlag (line 137) | type dnsTTLFlag struct
    method Set (line 139) | func (f *dnsTTLFlag) Set(v string) (err error) {
    method String (line 149) | func (f *dnsTTLFlag) String() string {
  constant connectToFormat (line 158) | connectToFormat = "src:port:dst:port"
  type connectToFlag (line 160) | type connectToFlag struct
    method String (line 164) | func (c *connectToFlag) String() string {
    method Set (line 178) | func (c *connectToFlag) Set(s string) error {

FILE: internal/cmd/echosrv/main.go
  function main (line 18) | func main() {
  function hash (line 57) | func hash(n int) (string, error) {

FILE: internal/cmd/jsonschema/main.go
  function main (line 15) | func main() {
  function die (line 52) | func die(s string, args ...interface{}) {
  function keys (line 57) | func keys(types map[string]interface{}) (ks []string) {

FILE: internal/resolver/resolver.go
  type resolver (line 13) | type resolver struct
    method dial (line 72) | func (r *resolver) dial(ctx context.Context, network, _ string) (net.C...
    method address (line 76) | func (r *resolver) address() string {
  function NewResolver (line 24) | func NewResolver(addrs []string) (*net.Resolver, error) {
  function normalizeAddrs (line 38) | func normalizeAddrs(addrs []string) ([]string, error) {

FILE: internal/resolver/resolver_test.go
  constant fakeDomain (line 20) | fakeDomain = "acme.notadomain"
  function TestResolver (line 23) | func TestResolver(t *testing.T) {
  function TestNormalizeAddrs (line 114) | func TestNormalizeAddrs(t *testing.T) {

FILE: lib/attack.go
  type Attacker (line 22) | type Attacker struct
    method Attack (line 446) | func (a *Attacker) Attack(tr Targeter, p Pacer, du time.Duration, name...
    method Stop (line 519) | func (a *Attacker) Stop() bool {
    method attack (line 529) | func (a *Attacker) attack(tr Targeter, atk *attack, workers *sync.Wait...
    method hit (line 536) | func (a *Attacker) hit(tr Targeter, atk *attack) *Result {
  constant DefaultRedirects (line 40) | DefaultRedirects = 10
  constant DefaultTimeout (line 43) | DefaultTimeout = 30 * time.Second
  constant DefaultConnections (line 46) | DefaultConnections = 10000
  constant DefaultMaxConnections (line 49) | DefaultMaxConnections = 0
  constant DefaultWorkers (line 51) | DefaultWorkers = 10
  constant DefaultMaxWorkers (line 53) | DefaultMaxWorkers = math.MaxUint64
  constant DefaultMaxBody (line 56) | DefaultMaxBody = int64(-1)
  constant NoFollow (line 58) | NoFollow = -1
  function NewAttacker (line 70) | func NewAttacker(opts ...func(*Attacker)) *Attacker {
  function Workers (line 105) | func Workers(n uint64) func(*Attacker) {
  function MaxWorkers (line 111) | func MaxWorkers(n uint64) func(*Attacker) {
  function Connections (line 117) | func Connections(n int) func(*Attacker) {
  function MaxConnections (line 126) | func MaxConnections(n int) func(*Attacker) {
  function ChunkedBody (line 135) | func ChunkedBody(b bool) func(*Attacker) {
  function Redirects (line 141) | func Redirects(n int) func(*Attacker) {
  function Proxy (line 159) | func Proxy(proxy func(*http.Request) (*url.URL, error)) func(*Attacker) {
  function Timeout (line 168) | func Timeout(d time.Duration) func(*Attacker) {
  function LocalAddr (line 176) | func LocalAddr(addr net.IPAddr) func(*Attacker) {
  function KeepAlive (line 186) | func KeepAlive(keepalive bool) func(*Attacker) {
  function TLSConfig (line 199) | func TLSConfig(c *tls.Config) func(*Attacker) {
  function HTTP2 (line 208) | func HTTP2(enabled bool) func(*Attacker) {
  function H2C (line 221) | func H2C(enabled bool) func(*Attacker) {
  function MaxBody (line 236) | func MaxBody(n int64) func(*Attacker) {
  function UnixSocket (line 241) | func UnixSocket(socket string) func(*Attacker) {
  function SessionTickets (line 253) | func SessionTickets(enabled bool) func(*Attacker) {
  function Client (line 264) | func Client(c *http.Client) func(*Attacker) {
  function ProxyHeader (line 270) | func ProxyHeader(h http.Header) func(*Attacker) {
  function ConnectTo (line 281) | func ConnectTo(addrMap map[string][]string) func(*Attacker) {
  function DNSCaching (line 323) | func DNSCaching(ttl time.Duration) func(*Attacker) {
  function firstOfEachIPFamily (line 408) | func firstOfEachIPFamily(ips []string) []string {
  type attack (line 434) | type attack struct

FILE: lib/attack_fuzz.go
  function FuzzAttackerTCP (line 16) | func FuzzAttackerTCP(fuzz []byte) int {
  function FuzzAttackerHTTP (line 72) | func FuzzAttackerHTTP(fuzz []byte) int {
  function decodeFuzzResponse (line 131) | func decodeFuzzResponse(fuzz []byte) (

FILE: lib/attack_test.go
  function TestAttackRate (line 25) | func TestAttackRate(t *testing.T) {
  function TestAttackDuration (line 43) | func TestAttackDuration(t *testing.T) {
  function TestTLSConfig (line 67) | func TestTLSConfig(t *testing.T) {
  function TestRedirects (line 75) | func TestRedirects(t *testing.T) {
  function TestNoFollow (line 93) | func TestNoFollow(t *testing.T) {
  function TestTimeout (line 112) | func TestTimeout(t *testing.T) {
  function TestLocalAddr (line 134) | func TestLocalAddr(t *testing.T) {
  function TestKeepAlive (line 156) | func TestKeepAlive(t *testing.T) {
  function TestSessionTickets (line 170) | func TestSessionTickets(t *testing.T) {
  function TestConnections (line 182) | func TestConnections(t *testing.T) {
  function TestStatusCodeErrors (line 191) | func TestStatusCodeErrors(t *testing.T) {
  function TestBadTargeterError (line 208) | func TestBadTargeterError(t *testing.T) {
  function TestResponseBodyCapture (line 218) | func TestResponseBodyCapture(t *testing.T) {
  function TestProxyOption (line 237) | func TestProxyOption(t *testing.T) {
  function TestMaxBody (line 268) | func TestMaxBody(t *testing.T) {
  function TestUnixSocket (line 298) | func TestUnixSocket(t *testing.T) {
  function TestClient (line 348) | func TestClient(t *testing.T) {
  function TestVegetaHeaders (line 382) | func TestVegetaHeaders(t *testing.T) {
  function TestDNSCaching_Issue649 (line 415) | func TestDNSCaching_Issue649(t *testing.T) {
  function TestFirstOfEachIPFamily (line 427) | func TestFirstOfEachIPFamily(t *testing.T) {
  function TestAttackConnectTo (line 503) | func TestAttackConnectTo(t *testing.T) {

FILE: lib/histogram.go
  type Buckets (line 11) | type Buckets
    method Nth (line 59) | func (bs Buckets) Nth(i int) (left, right string) {
    method UnmarshalText (line 67) | func (bs *Buckets) UnmarshalText(value []byte) error {
  type Histogram (line 14) | type Histogram struct
    method Add (line 23) | func (h *Histogram) Add(r *Result) {
    method MarshalJSON (line 40) | func (h *Histogram) MarshalJSON() ([]byte, error) {

FILE: lib/histogram_test.go
  function TestHistogram_Add (line 9) | func TestHistogram_Add(t *testing.T) {
  function TestBuckets_UnmarshalText (line 42) | func TestBuckets_UnmarshalText(t *testing.T) {

FILE: lib/lttb/lttb.go
  type Point (line 6) | type Point struct
  type Iter (line 10) | type Iter
  function Downsample (line 20) | func Downsample(count, threshold int, it Iter) ([]Point, error) {
  function sample (line 71) | func sample(a Point, current, next []Point) (b Point) {

FILE: lib/lttb/lttb_test.go
  function TestDownsample (line 14) | func TestDownsample(t *testing.T) {
  function BenchmarkLTTB (line 84) | func BenchmarkLTTB(b *testing.B) {
  function newIterator (line 99) | func newIterator(data []Point) Iter {

FILE: lib/metrics.go
  type Metrics (line 12) | type Metrics struct
    method Add (line 50) | func (m *Metrics) Add(r *Result) {
    method Close (line 90) | func (m *Metrics) Close() {
    method init (line 117) | func (m *Metrics) init() {
  type LatencyMetrics (line 132) | type LatencyMetrics struct
    method Add (line 154) | func (l *LatencyMetrics) Add(latency time.Duration) {
    method Quantile (line 166) | func (l LatencyMetrics) Quantile(nth float64) time.Duration {
    method init (line 171) | func (l *LatencyMetrics) init() {
  type ByteMetrics (line 180) | type ByteMetrics struct
  type estimator (line 187) | type estimator interface
  type tdigestEstimator (line 192) | type tdigestEstimator struct
    method Add (line 198) | func (e *tdigestEstimator) Add(s float64) { e.TDigest.Add(s, 1) }
    method Get (line 199) | func (e *tdigestEstimator) Get(q float64) float64 {
  function newTdigestEstimator (line 194) | func newTdigestEstimator(compression float64) *tdigestEstimator {

FILE: lib/metrics_test.go
  function TestMetrics_Add (line 17) | func TestMetrics_Add(t *testing.T) {
  function equateApproxDuration (line 88) | func equateApproxDuration(margin time.Duration) cmp.Option {
  function areNonZeroDurations (line 96) | func areNonZeroDurations(x, y time.Duration) bool {
  type durationApproximator (line 100) | type durationApproximator struct
    method compare (line 104) | func (a durationApproximator) compare(x, y time.Duration) bool {
  function TestMetrics_NoInfiniteRate (line 116) | func TestMetrics_NoInfiniteRate(t *testing.T) {
  function TestMetrics_NonNilErrorsOnClose (line 128) | func TestMetrics_NonNilErrorsOnClose(t *testing.T) {
  function TestMetrics_EmptyMetricsCanBeReported (line 142) | func TestMetrics_EmptyMetricsCanBeReported(t *testing.T) {
  function BenchmarkMetrics (line 153) | func BenchmarkMetrics(b *testing.B) {
  type bmizeranyEstimator (line 206) | type bmizeranyEstimator struct
    method Add (line 214) | func (e *bmizeranyEstimator) Add(s float64) { e.Insert(s) }
    method Get (line 215) | func (e *bmizeranyEstimator) Get(q float64) float64 {
  function newBmizeranyEstimator (line 210) | func newBmizeranyEstimator(qs ...float64) *bmizeranyEstimator {
  type dgryskiEstimator (line 219) | type dgryskiEstimator struct
    method Add (line 227) | func (e *dgryskiEstimator) Add(s float64) { e.Insert(s) }
    method Get (line 228) | func (e *dgryskiEstimator) Get(q float64) float64 {
  function newDgriskyEstimator (line 223) | func newDgriskyEstimator(epsilon float64) *dgryskiEstimator {

FILE: lib/pacer.go
  type Pacer (line 10) | type Pacer interface
  type PacerFunc (line 24) | type PacerFunc
    method Pace (line 27) | func (pf PacerFunc) Pace(elapsed time.Duration, hits uint64) (time.Dur...
  type ConstantPacer (line 32) | type ConstantPacer struct
    method String (line 46) | func (cp ConstantPacer) String() string {
    method Pace (line 51) | func (cp ConstantPacer) Pace(elapsed time.Duration, hits uint64) (time...
    method Rate (line 77) | func (cp ConstantPacer) Rate(elapsed time.Duration) float64 {
    method hitsPerNs (line 83) | func (cp ConstantPacer) hitsPerNs() float64 {
  constant MeanUp (line 90) | MeanUp float64 = 0
  constant Peak (line 93) | Peak = math.Pi / 2
  constant MeanDown (line 96) | MeanDown = math.Pi
  constant Trough (line 99) | Trough = 3 * math.Pi / 2
  type SinePacer (line 140) | type SinePacer struct
    method String (line 166) | func (sp SinePacer) String() string {
    method invalid (line 171) | func (sp SinePacer) invalid() bool {
    method Pace (line 176) | func (sp SinePacer) Pace(elapsedTime time.Duration, elapsedHits uint64...
    method Rate (line 209) | func (sp SinePacer) Rate(elapsed time.Duration) float64 {
    method ampHits (line 216) | func (sp SinePacer) ampHits() float64 {
    method radians (line 223) | func (sp SinePacer) radians(t time.Duration) float64 {
    method hitsPerNs (line 231) | func (sp SinePacer) hitsPerNs(t time.Duration) float64 {
    method hits (line 244) | func (sp SinePacer) hits(t time.Duration) float64 {
  type LinearPacer (line 253) | type LinearPacer struct
    method Pace (line 259) | func (p LinearPacer) Pace(elapsed time.Duration, hits uint64) (time.Du...
    method Rate (line 289) | func (p LinearPacer) Rate(elapsed time.Duration) float64 {
    method hits (line 299) | func (p LinearPacer) hits(t time.Duration) float64 {

FILE: lib/pacer_test.go
  function TestConstantPacer (line 11) | func TestConstantPacer(t *testing.T) {
  function TestConstantPacer_Rate (line 68) | func TestConstantPacer_Rate(t *testing.T) {
  function floatEqual (line 102) | func floatEqual(x, y float64) bool {
  function durationEqual (line 110) | func durationEqual(x, y time.Duration) bool {
  type sineTest (line 159) | type sineTest struct
    method Pacer (line 165) | func (st sineTest) Pacer(startAt float64) SinePacer {
    method ampHits (line 175) | func (st sineTest) ampHits() float64 {
  function TestSinePacerHits (line 179) | func TestSinePacerHits(t *testing.T) {
  function TestSinePacerInvalid (line 212) | func TestSinePacerInvalid(t *testing.T) {
  function TestSinePacerPace_Flat (line 233) | func TestSinePacerPace_Flat(t *testing.T) {
  function TestSincePacer_Rate (line 262) | func TestSincePacer_Rate(t *testing.T) {
  function TestLinearPacer (line 291) | func TestLinearPacer(t *testing.T) {
  function TestLinearPacer_hits (line 364) | func TestLinearPacer_hits(t *testing.T) {
  function TestLinearPacer_Rate (line 392) | func TestLinearPacer_Rate(t *testing.T) {

FILE: lib/plot/assets/uplot-plugins.js
  function pivotData (line 2) | function pivotData(rowData) {
  function formatDuration (line 18) | function formatDuration(ms) {
  function exportToPNG (line 39) | function exportToPNG(uplotInstance, filename) {

FILE: lib/plot/embed.go
  type embedFS (line 19) | type embedFS struct
    method Open (line 23) | func (e *embedFS) Open(name string) (http.File, error) {
  type embedFile (line 52) | type embedFile struct
    method Readdir (line 56) | func (f *embedFile) Readdir(count int) ([]os.FileInfo, error) {
    method Seek (line 60) | func (f *embedFile) Seek(offset int64, whence int) (int64, error) {
  type embedFileSeeker (line 64) | type embedFileSeeker struct
    method Read (line 70) | func (f *embedFileSeeker) Read(p []byte) (int, error) {
    method Seek (line 74) | func (f *embedFileSeeker) Seek(offset int64, whence int) (int64, error) {
    method Readdir (line 78) | func (f *embedFileSeeker) Readdir(count int) ([]os.FileInfo, error) {
  type bytesReaderAt (line 82) | type bytesReaderAt struct
    method ReadAt (line 86) | func (r *bytesReaderAt) ReadAt(p []byte, off int64) (n int, err error) {

FILE: lib/plot/plot.go
  type Plot (line 20) | type Plot struct
    method Add (line 148) | func (p *Plot) Add(r *vegeta.Result) error {
    method Close (line 158) | func (p *Plot) Close() {
    method WriteTo (line 167) | func (p *Plot) WriteTo(w io.Writer) (n int64, err error) {
    method data (line 269) | func (p *Plot) data() (dataPoints, []string, error) {
  type Labeler (line 30) | type Labeler
  function ErrorLabeler (line 35) | func ErrorLabeler(r *vegeta.Result) (label string) {
  type labeledSeries (line 47) | type labeledSeries struct
    method add (line 71) | func (ls *labeledSeries) add(r *vegeta.Result) (err error) {
  type point (line 56) | type point struct
  function newLabeledSeries (line 63) | func newLabeledSeries(label Labeler) *labeledSeries {
  type Opt (line 113) | type Opt
  function Title (line 116) | func Title(title string) Opt {
  function Downsample (line 122) | func Downsample(threshold int) Opt {
  function Label (line 128) | func Label(l Labeler) Opt {
  function New (line 134) | func New(opts ...Opt) *Plot {
  function labelColors (line 249) | func labelColors(labels []string) []string {
  function asset (line 321) | func asset(path string) ([]byte, error) {
  type countingWriter (line 329) | type countingWriter struct
    method Write (line 334) | func (cw *countingWriter) Write(p []byte) (int, error) {
  type dataPoints (line 340) | type dataPoints
    method Len (line 342) | func (ps dataPoints) Len() int { return len(ps) }
    method Less (line 344) | func (ps dataPoints) Less(i, j int) bool {
    method Swap (line 349) | func (ps dataPoints) Swap(i, j int) {
    method Append (line 353) | func (ps dataPoints) Append(buf []byte) []byte {

FILE: lib/plot/plot_test.go
  function TestPlot (line 21) | func TestPlot(t *testing.T) {
  function TestLabeledSeries (line 69) | func TestLabeledSeries(t *testing.T) {
  function BenchmarkPlot (line 132) | func BenchmarkPlot(b *testing.B) {

FILE: lib/plot/timeseries.go
  type timeSeries (line 13) | type timeSeries struct
    method add (line 31) | func (ts *timeSeries) add(t uint64, v float64) error {
    method iter (line 43) | func (ts *timeSeries) iter() lttb.Iter {
  function newTimeSeries (line 21) | func newTimeSeries(attack, label string) *timeSeries {

FILE: lib/prom/prom.go
  type Metrics (line 16) | type Metrics struct
    method Register (line 49) | func (pm *Metrics) Register(r prometheus.Registerer) error {
    method Observe (line 64) | func (pm *Metrics) Observe(res *vegeta.Result) {
  function NewMetrics (line 25) | func NewMetrics() *Metrics {
  function NewHandler (line 76) | func NewHandler(r *prometheus.Registry, startTime time.Time) http.Handler {

FILE: lib/prom/prom_test.go
  function TestMetrics_Observe (line 15) | func TestMetrics_Observe(t *testing.T) {

FILE: lib/reporters.go
  type Report (line 14) | type Report interface
  type Closer (line 20) | type Closer interface
  type Reporter (line 27) | type Reporter
    method Report (line 30) | func (rep Reporter) Report(w io.Writer) error { return rep(w) }
  function NewHistogramReporter (line 34) | func NewHistogramReporter(h *Histogram) Reporter {
  function NewTextReporter (line 57) | func NewTextReporter(m *Metrics) Reporter {
  function round (line 125) | func round(d time.Duration) time.Duration {
  function NewJSONReporter (line 135) | func NewJSONReporter(m *Metrics) Reporter {
  function NewHDRHistogramPlotReporter (line 240) | func NewHDRHistogramPlotReporter(m *Metrics) Reporter {
  function milliseconds (line 269) | func milliseconds(d time.Duration) float64 {
  function oneByQuantile (line 274) | func oneByQuantile(q float64) float64 {

FILE: lib/results.go
  function init (line 21) | func init() {
  type Result (line 26) | type Result struct
    method End (line 42) | func (r *Result) End() time.Time { return r.Timestamp.Add(r.Latency) }
    method Equal (line 45) | func (r Result) Equal(other Result) bool {
  function headerEqual (line 60) | func headerEqual(h1, h2 http.Header) bool {
  type Results (line 83) | type Results
    method Add (line 87) | func (rs *Results) Add(r *Result) { *rs = append(*rs, *r) }
    method Close (line 91) | func (rs *Results) Close() { sort.Sort(rs) }
    method Len (line 94) | func (rs Results) Len() int           { return len(rs) }
    method Less (line 95) | func (rs Results) Less(i, j int) bool { return rs[i].Timestamp.Before(...
    method Swap (line 96) | func (rs Results) Swap(i, j int)      { rs[i], rs[j] = rs[j], rs[i] }
  type Decoder (line 99) | type Decoder
    method Decode (line 152) | func (dec Decoder) Decode(r *Result) error { return dec(r) }
  type DecoderFactory (line 102) | type DecoderFactory
  function DecoderFor (line 107) | func DecoderFor(r io.Reader) Decoder {
  function NewRoundRobinDecoder (line 124) | func NewRoundRobinDecoder(dec ...Decoder) Decoder {
  function NewDecoder (line 145) | func NewDecoder(rd io.Reader) Decoder {
  type Encoder (line 155) | type Encoder
    method Encode (line 165) | func (enc Encoder) Encode(r *Result) error { return enc(r) }
  function NewEncoder (line 158) | func NewEncoder(r io.Writer) Encoder {
  function NewCSVEncoder (line 171) | func NewCSVEncoder(w io.Writer) Encoder {
  function headerBytes (line 198) | func headerBytes(h http.Header) []byte {
  function NewCSVDecoder (line 208) | func NewCSVDecoder(r io.Reader) Decoder {
  type jsonResult (line 274) | type jsonResult
  function NewJSONEncoder (line 278) | func NewJSONEncoder(w io.Writer) Encoder {
  function NewJSONDecoder (line 292) | func NewJSONDecoder(r io.Reader) Decoder {

FILE: lib/results_easyjson.go
  function easyjsonBd1621b8DecodeGithubComTsenartVegetaV12Lib (line 23) | func easyjsonBd1621b8DecodeGithubComTsenartVegetaV12Lib(in *jlexer.Lexer...
  function easyjsonBd1621b8EncodeGithubComTsenartVegetaV12Lib (line 118) | func easyjsonBd1621b8EncodeGithubComTsenartVegetaV12Lib(out *jwriter.Wri...
  method MarshalEasyJSON (line 213) | func (v jsonResult) MarshalEasyJSON(w *jwriter.Writer) {
  method UnmarshalEasyJSON (line 218) | func (v *jsonResult) UnmarshalEasyJSON(l *jlexer.Lexer) {

FILE: lib/results_fuzz.go
  function FuzzResultsFormatDetection (line 12) | func FuzzResultsFormatDetection(fuzz []byte) int {
  function FuzzGobDecoder (line 25) | func FuzzGobDecoder(fuzz []byte) int {
  function FuzzCSVDecoder (line 35) | func FuzzCSVDecoder(fuzz []byte) int {
  function FuzzJSONDecoder (line 45) | func FuzzJSONDecoder(fuzz []byte) int {
  function readAllResults (line 54) | func readAllResults(decoder Decoder) (ok bool) {

FILE: lib/results_test.go
  function TestResultDecoding (line 17) | func TestResultDecoding(t *testing.T) {
  function TestResultEncoding (line 55) | func TestResultEncoding(t *testing.T) {
  function BenchmarkResultEncodings (line 145) | func BenchmarkResultEncodings(b *testing.B) {

FILE: lib/targets.go
  type Target (line 24) | type Target struct
    method Request (line 33) | func (t *Target) Request() (*http.Request, error) {
    method Equal (line 57) | func (t *Target) Equal(other *Target) bool {
  constant HTTPTargetFormat (line 107) | HTTPTargetFormat = "http"
  constant JSONTargetFormat (line 109) | JSONTargetFormat = "json"
  type Targeter (line 114) | type Targeter
    method Decode (line 117) | func (tr Targeter) Decode(t *Target) error {
  function NewJSONTargeter (line 132) | func NewJSONTargeter(src io.Reader, body []byte, header http.Header) Tar...
  type TargetEncoder (line 196) | type TargetEncoder
    method Encode (line 199) | func (enc TargetEncoder) Encode(t *Target) error {
  function NewJSONTargetEncoder (line 204) | func NewJSONTargetEncoder(w io.Writer) TargetEncoder {
  function NewStaticTargeter (line 219) | func NewStaticTargeter(tgts ...Target) Targeter {
  function ReadAllTargets (line 231) | func ReadAllTargets(t Targeter) (tgts []Target, err error) {
  function NewHTTPTargeter (line 262) | func NewHTTPTargeter(src io.Reader, body []byte, hdr http.Header) Target...
  function startsWithHTTPMethod (line 343) | func startsWithHTTPMethod(t string) bool {
  type peekingScanner (line 349) | type peekingScanner struct
    method Err (line 354) | func (s *peekingScanner) Err() error {
    method Peek (line 358) | func (s *peekingScanner) Peek() string {
    method Scan (line 366) | func (s *peekingScanner) Scan() bool {
    method Text (line 373) | func (s *peekingScanner) Text() string {

FILE: lib/targets_easyjson.go
  type jsonTarget (line 13) | type jsonTarget
    method decode (line 15) | func (t *jsonTarget) decode(in *jlexer.Lexer) {
    method encode (line 97) | func (t jsonTarget) encode(out *jwriter.Writer) {

FILE: lib/targets_fuzz.go
  function FuzzHTTPTargeter (line 12) | func FuzzHTTPTargeter(fuzz []byte) int {
  function FuzzJSONTargeter (line 30) | func FuzzJSONTargeter(fuzz []byte) int {
  function decodeFuzzTargetDefaults (line 47) | func decodeFuzzTargetDefaults(fuzz []byte) (

FILE: lib/targets_test.go
  function TestTargetRequest (line 16) | func TestTargetRequest(t *testing.T) {
  function TestTargetRequest_EmptyBody (line 60) | func TestTargetRequest_EmptyBody(t *testing.T) {
  function TestJSONTargeter (line 93) | func TestJSONTargeter(t *testing.T) {
  function TestReadAllTargets (line 204) | func TestReadAllTargets(t *testing.T) {
  type errReader (line 282) | type errReader struct
    method Read (line 284) | func (e errReader) Read(p []byte) (n int, err error) {
  function TestNewHTTPTargeter (line 288) | func TestNewHTTPTargeter(t *testing.T) {
  function TestErrNilTarget (line 441) | func TestErrNilTarget(t *testing.T) {
  function BenchmarkJSONTargetEncoding (line 455) | func BenchmarkJSONTargetEncoding(b *testing.B) {

FILE: lib/util_fuzz.go
  function decodeFuzzHeaders (line 6) | func decodeFuzzHeaders(fuzz []byte, headers map[string][]string) (
  function decodeFuzzHeader (line 38) | func decodeFuzzHeader(fuzz []byte, headers map[string][]string) (
  function extractFuzzString (line 63) | func extractFuzzString(fuzz []byte) (
  function extractFuzzByteString (line 93) | func extractFuzzByteString(fuzz []byte) (

FILE: main.go
  function main (line 14) | func main() {
  constant examples (line 106) | examples = `
  type command (line 114) | type command struct

FILE: plot.go
  constant plotUsage (line 14) | plotUsage = `Usage: vegeta plot [options] [<file>...]
  function plotCmd (line 43) | func plotCmd() command {
  function plotRun (line 63) | func plotRun(files []string, threshold int, title, output string) error {

FILE: report.go
  constant reportUsage (line 15) | reportUsage = `Usage: vegeta report [options] [<file>...]
  function reportCmd (line 40) | func reportCmd() command {
  function report (line 61) | func report(files []string, typ, output string, every time.Duration, buc...
  function writeReport (line 158) | func writeReport(r vegeta.Reporter, rc vegeta.Closer, out io.Writer) err...
  function clear (line 165) | func clear(out io.Writer) error {

FILE: report_nonwindows.go
  function clearScreen (line 12) | func clearScreen() error {

FILE: report_windows.go
  function clearScreen (line 11) | func clearScreen() error {
Condensed preview — 70 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (834K chars).
[
  {
    "path": ".github/CODEOWNERS",
    "chars": 15,
    "preview": "* @tsenart @xla"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 744,
    "preview": "# Contributing\n\nNon trivial changes should be discussed with the project maintainers by\nopening a [Feature Request](http"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 815,
    "preview": "---\nname: 🐛  Bug Report\nabout: Report a bug to help Vegeta improve.\n---\n\n<!-- ⚠️ If you do not respect this template you"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 577,
    "preview": "---\nname: 🚀  Feature Request\nabout: Propose a change to Vegeta💡!\n---\n\n<!-- ⚠️ If you do not respect this template your i"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/question.md",
    "chars": 108,
    "preview": "---\nname: ❓ Question\nabout: Ask a question that isn't a feature request nor a bug report.\n---\n\n#### Question"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 398,
    "preview": "#### Background\n\n<!-- Required background information to understand the PR. Link here any related issues. -->\n\n#### Chec"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 433,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 4209,
    "preview": "name: CI\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n    branches:\n      - master\n  pull_request:\n    types: [opened, synchro"
  },
  {
    "path": ".gitignore",
    "chars": 336,
    "preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture spe"
  },
  {
    "path": "CHANGELOG",
    "chars": 2548,
    "preview": "2018-05-18: v7.0.0\n  Include response body in hit results (#279)\n  Added support for h2c requests (HTTP/2 without TLS) ("
  },
  {
    "path": "Dockerfile",
    "chars": 306,
    "preview": "FROM golang:1.20-alpine3.18 AS BUILD\n\nRUN apk add make build-base git\n\nWORKDIR /vegeta\n\n# cache dependencies\nADD go.mod "
  },
  {
    "path": "LICENSE",
    "chars": 1084,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2013-2023 Tomás Senart\n\nPermission is hereby granted, free of charge, to any person"
  },
  {
    "path": "Makefile",
    "chars": 558,
    "preview": "COMMIT=$(shell git rev-parse HEAD)\nVERSION=$(shell git describe --tags --exact-match --always)\nDATE=$(shell date +'%FT%T"
  },
  {
    "path": "README.md",
    "chars": 31707,
    "preview": "# Vegeta [![Build Status](https://github.com/tsenart/vegeta/workflows/CI/badge.svg)](https://github.com/tsenart/vegeta/a"
  },
  {
    "path": "attack.go",
    "chars": 9286,
    "preview": "package main\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\""
  },
  {
    "path": "attack_nonwindows.go",
    "chars": 287,
    "preview": "//go:build !windows\n// +build !windows\n\npackage main\n\nimport \"flag\"\n\nfunc systemSpecificFlags(fs *flag.FlagSet, opts *at"
  },
  {
    "path": "attack_test.go",
    "chars": 3957,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"os\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\t\"ti"
  },
  {
    "path": "attack_windows.go",
    "chars": 93,
    "preview": "package main\n\nimport \"flag\"\n\nfunc systemSpecificFlags(fs *flag.FlagSet, opts *attackOpts) {}\n"
  },
  {
    "path": "dump.go",
    "chars": 205,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n)\n\nfunc dumpCmd() command {\n\treturn command{fn: func([]string) error {\n\t\treturn fmt.Errorf"
  },
  {
    "path": "encode.go",
    "chars": 2624,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\n\tvegeta \"github.com/tsenart/vegeta/v12/lib\"\n)"
  },
  {
    "path": "file.go",
    "chars": 1131,
    "preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\tvegeta \"github.com/tsenart/vegeta/v12/lib\"\n)\n\nfunc file"
  },
  {
    "path": "flags.go",
    "chars": 4418,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/c2"
  },
  {
    "path": "go.mod",
    "chars": 1863,
    "preview": "module github.com/tsenart/vegeta/v12\n\ngo 1.22\n\nrequire (\n\tgithub.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9"
  },
  {
    "path": "go.sum",
    "chars": 15813,
    "preview": "github.com/alecthomas/jsonschema v0.0.0-20220216202328-9eeeec9d044b h1:doCpXjVwui6HUN+xgNsNS3SZ0/jUZ68Eb+mJRNOZfog=\ngith"
  },
  {
    "path": "internal/cmd/echosrv/main.go",
    "chars": 1439,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"flag\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"ne"
  },
  {
    "path": "internal/cmd/jsonschema/main.go",
    "chars": 1126,
    "preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/alecthomas/jsonschema\"\n\n\tvegeta \"g"
  },
  {
    "path": "internal/resolver/resolver.go",
    "chars": 1840,
    "preview": "package resolver\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n)\n\ntype resolver stru"
  },
  {
    "path": "internal/resolver/resolver_test.go",
    "chars": 3562,
    "preview": "package resolver\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"string"
  },
  {
    "path": "lib/attack.go",
    "chars": 15643,
    "preview": "package vegeta\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strc"
  },
  {
    "path": "lib/attack_fuzz.go",
    "chars": 2934,
    "preview": "//go:build gofuzz\n// +build gofuzz\n\npackage vegeta\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n"
  },
  {
    "path": "lib/attack_test.go",
    "chars": 14490,
    "preview": "package vegeta\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\""
  },
  {
    "path": "lib/histogram.go",
    "chars": 1998,
    "preview": "package vegeta\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Buckets represents an Histogram's latency buckets.\ntyp"
  },
  {
    "path": "lib/histogram_test.go",
    "chars": 1705,
    "preview": "package vegeta\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestHistogram_Add(t *testing.T) {\n\tt.Parallel()\n\thist := "
  },
  {
    "path": "lib/lttb/lttb.go",
    "chars": 2653,
    "preview": "package lttb\n\nimport \"errors\"\n\n// A Point in a line chart.\ntype Point struct{ X, Y float64 }\n\n// An Iter is an iterator "
  },
  {
    "path": "lib/lttb/lttb_test.go",
    "chars": 389634,
    "preview": "package lttb\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"sync\"\n\t\"testing\"\n\t\"unsafe\"\n\n\tgolttb \"github.com/dgryski/go-lttb\"\n\t\"github.com"
  },
  {
    "path": "lib/metrics.go",
    "chars": 5798,
    "preview": "package vegeta\n\nimport (\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/influxdata/tdigest\"\n)\n\n// Metrics holds metrics computed out o"
  },
  {
    "path": "lib/metrics_test.go",
    "chars": 5339,
    "preview": "package vegeta\n\nimport (\n\t\"io\"\n\t\"math/rand\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\tbmizerany \"github.com/bmizerany/perks/quanti"
  },
  {
    "path": "lib/pacer.go",
    "chars": 10675,
    "preview": "package vegeta\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n)\n\n// A Pacer defines the rate of hits during an Attack.\ntype Pacer inte"
  },
  {
    "path": "lib/pacer_test.go",
    "chars": 12741,
    "preview": "package vegeta\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"testing\"\n\t\"testing/quick\"\n\t\"time\"\n)\n\nfunc TestConstantPacer(t *testing.T) "
  },
  {
    "path": "lib/plot/assets/VERSIONS",
    "chars": 14,
    "preview": "uPlot v1.6.32\n"
  },
  {
    "path": "lib/plot/assets/plot.html.tpl",
    "chars": 10024,
    "preview": "<!doctype html>\n<html>\n<head>\n  <title>{{.Title}}</title>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"widt"
  },
  {
    "path": "lib/plot/assets/uplot-plugins.js",
    "chars": 1400,
    "preview": "// Data pivoting: Convert row-oriented data to column-oriented for uPlot\nfunction pivotData(rowData) {\n  if (!rowData ||"
  },
  {
    "path": "lib/plot/assets.go",
    "chars": 171,
    "preview": "//go:build dev\n// +build dev\n\npackage plot\n\nimport (\n\t\"net/http\"\n)\n\n// Assets contains assets required to render the Plo"
  },
  {
    "path": "lib/plot/embed.go",
    "chars": 1630,
    "preview": "//go:build !dev\n\npackage plot\n\nimport (\n\t\"embed\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n)\n\n//go:embed assets/*\nvar assetsFS em"
  },
  {
    "path": "lib/plot/plot.go",
    "chars": 7684,
    "preview": "package plot\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"html/template\"\n\t\"io\"\n\t\"math\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tve"
  },
  {
    "path": "lib/plot/plot_test.go",
    "chars": 3404,
    "preview": "package plot\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"io\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.c"
  },
  {
    "path": "lib/plot/testdata/TestPlot.golden.html",
    "chars": 96023,
    "preview": "<!doctype html>\n<html>\n<head>\n  <title>TestPlot</title>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width="
  },
  {
    "path": "lib/plot/timeseries.go",
    "chars": 1087,
    "preview": "package plot\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\ttsz \"github.com/tsenart/go-tsz\"\n\t\"github.com/tsenart/vegeta/v12/lib/lttb\"\n)\n\n"
  },
  {
    "path": "lib/prom/grafana.json",
    "chars": 14257,
    "preview": "{\n  \"__inputs\": [\n    {\n      \"name\": \"DS_PROMETHEUS\",\n      \"label\": \"prometheus\",\n      \"description\": \"\",\n      \"type"
  },
  {
    "path": "lib/prom/prom.go",
    "chars": 2749,
    "preview": "package prom\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/prometheus\"\n\t\"github"
  },
  {
    "path": "lib/prom/prom_test.go",
    "chars": 1985,
    "preview": "package prom\n\nimport (\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/prometheus/client_golang/"
  },
  {
    "path": "lib/reporters.go",
    "chars": 5876,
    "preview": "package vegeta\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\t\"text/tabwriter\"\n\t\"time\"\n)\n\n// A Report repre"
  },
  {
    "path": "lib/results.go",
    "chars": 7707,
    "preview": "package vegeta\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/csv\"\n\t\"encoding/gob\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/te"
  },
  {
    "path": "lib/results_easyjson.go",
    "chars": 4631,
    "preview": "// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.\n\npackage vegeta\n\nimport (\n\tjson \"encoding/json\"\n"
  },
  {
    "path": "lib/results_fuzz.go",
    "chars": 1187,
    "preview": "//go:build gofuzz\n// +build gofuzz\n\npackage vegeta\n\nimport (\n\t\"bytes\"\n\t\"io\"\n)\n\n// FuzzResultsFormatDetection tests resul"
  },
  {
    "path": "lib/results_test.go",
    "chars": 4681,
    "preview": "package vegeta\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"githu"
  },
  {
    "path": "lib/target.schema.json",
    "chars": 774,
    "preview": "{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"$ref\": \"#/definitions/Target\",\n  \"definitions\": {\n    \"Targ"
  },
  {
    "path": "lib/targets.go",
    "chars": 9145,
    "preview": "package vegeta\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"sy"
  },
  {
    "path": "lib/targets_easyjson.go",
    "chars": 3074,
    "preview": "// This file has been modified from the original generated code to make it work with\n// type alias jsonTarget so that th"
  },
  {
    "path": "lib/targets_fuzz.go",
    "chars": 1156,
    "preview": "//go:build gofuzz\n// +build gofuzz\n\npackage vegeta\n\nimport (\n\t\"bytes\"\n\t\"net/http\"\n)\n\n// FuzzHTTPTargeter tests decoding "
  },
  {
    "path": "lib/targets_test.go",
    "chars": 11292,
    "preview": "package vegeta\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testin"
  },
  {
    "path": "lib/util_fuzz.go",
    "chars": 1888,
    "preview": "//go:build gofuzz\n// +build gofuzz\n\npackage vegeta\n\nfunc decodeFuzzHeaders(fuzz []byte, headers map[string][]string) (\n\t"
  },
  {
    "path": "main.go",
    "chars": 2424,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"sort\"\n\t\"strings\"\n)\n\nfunc main() {\n\tcomm"
  },
  {
    "path": "plot.go",
    "chars": 2749,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\n\tvegeta \"github.com/tsenart/vegeta/v12/lib\"\n\t\"github.com"
  },
  {
    "path": "report.go",
    "chars": 3989,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"time\"\n\n\tvegeta \"github.com/tsenart/vegeta/v1"
  },
  {
    "path": "report_nonwindows.go",
    "chars": 193,
    "preview": "//go:build !windows\n// +build !windows\n\npackage main\n\nimport (\n\t\"os\"\n)\n\nvar escCodes = []byte(\"\\033[2J\\033[0;0H\")\n\nfunc "
  },
  {
    "path": "report_windows.go",
    "chars": 193,
    "preview": "//go:build windows\n// +build windows\n\npackage main\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n)\n\nfunc clearScreen() error {\n\tcmd := exec"
  },
  {
    "path": "scripts/load-ramping/README.md",
    "chars": 372,
    "preview": "# Load ramping\n\nThis script will automatically run vegeta against a target with different request\nrates and graph the la"
  },
  {
    "path": "scripts/load-ramping/ramp-requests.plt",
    "chars": 1642,
    "preview": "# Two plots: success rate plot on top, rate/latency distribution below\nset multiplot layout 2,1\n\n\n#\n# Shared config\n#\n\n#"
  },
  {
    "path": "scripts/load-ramping/ramp-requests.py",
    "chars": 2236,
    "preview": "#!/usr/bin/env python3\n\nimport json\nimport os\nimport subprocess\nimport sys\nimport time\n\n\nif '-h' in sys.argv or '--help'"
  }
]

About this extraction

This page contains the full source code of the tsenart/vegeta GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 70 files (742.9 KB), approximately 330.7k tokens, and a symbol index with 354 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!