Full Code of probelabs/goreplay for AI

master 251e45abd242 cached
162 files
655.8 KB
203.4k tokens
748 symbols
1 requests
Download .txt
Showing preview only (696K chars total). Download the full file or copy to clipboard to get everything.
Repository: probelabs/goreplay
Branch: master
Commit: 251e45abd242
Files: 162
Total size: 655.8 KB

Directory structure:
gitextract_1d_7z0pv/

├── .clabot
├── .deepsource.toml
├── .dockerignore
├── .github/
│   ├── dependabot.yaml
│   └── workflows/
│       ├── ci-docker.yaml
│       ├── ci-test.yaml
│       ├── codesee-arch-diagram.yml
│       ├── probe.yaml
│       └── semgrep.yml
├── .gitignore
├── .gitmodules
├── .request
├── COMM-LICENSE
├── Dockerfile
├── Dockerfile.dev
├── ELASTICSEARCH.md
├── LICENSE.txt
├── Makefile
├── Procfile
├── README.md
├── ce.go
├── circle.yml
├── docs/
│   ├── CNAME
│   ├── Capturing-and-replaying-traffic.md
│   ├── Compilation.md
│   ├── Development-Setup.md
│   ├── Distributed-configuration.md
│   ├── Exporting-to-ElasticSearch.md
│   ├── FAQ.md
│   ├── Middleware.md
│   ├── Rate-limiting.md
│   ├── Replaying-HTTP-traffic.md
│   ├── Request-filtering.md
│   ├── Request-rewriting.md
│   ├── Running-as-non-root-user.md
│   ├── Saving-and-Replaying-from-file.md
│   ├── Troubleshooting.md
│   ├── _Footer.md
│   ├── _config.yml
│   ├── commercial/
│   │   ├── collaboration.md
│   │   ├── faq.md
│   │   └── support.md
│   ├── css/
│   │   ├── breadcrumbs.css
│   │   ├── code.css
│   │   ├── fabric.css
│   │   ├── goreplay.css
│   │   └── sidenav.css
│   ├── getting-started/
│   │   ├── basics.md
│   │   └── tutorial.md
│   ├── index.md
│   ├── js/
│   │   ├── base.js
│   │   └── turbolinks.js
│   └── pro/
│       ├── recording-and-replaying-keep-alive-tcp-sessions.md
│       └── replaying-binary-protocols.md
├── elasticsearch.go
├── elasticsearch_test.go
├── emitter.go
├── emitter_test.go
├── examples/
│   └── middleware/
│       ├── echo.clj
│       ├── echo.java
│       ├── echo.js
│       ├── echo.py
│       ├── echo.rb
│       ├── echo.sh
│       └── token_modifier.go
├── go.mod
├── go.sum
├── gor_stat.go
├── homebrew/
│   └── gor.rb
├── http_modifier.go
├── http_modifier_settings.go
├── http_modifier_settings_test.go
├── http_modifier_test.go
├── http_prettifier.go
├── http_prettifier_test.go
├── input_dummy.go
├── input_file.go
├── input_file_test.go
├── input_http.go
├── input_http_test.go
├── input_kafka.go
├── input_kafka_test.go
├── input_raw.go
├── input_raw_test.go
├── input_tcp.go
├── input_tcp_test.go
├── internal/
│   ├── byteutils/
│   │   ├── byteutils.go
│   │   └── byteutils_test.go
│   ├── capture/
│   │   ├── af_packet.go
│   │   ├── af_packet_linux.go
│   │   ├── capture.go
│   │   ├── capture_test.go
│   │   ├── doc.go
│   │   ├── dump.go
│   │   ├── sock_linux.go
│   │   ├── sock_others.go
│   │   ├── socket.go
│   │   └── vxlan.go
│   ├── ring/
│   │   └── ring.go
│   ├── simpletime/
│   │   └── time.go
│   ├── size/
│   │   ├── size.go
│   │   └── size_test.go
│   └── tcp/
│       ├── doc.go
│       ├── tcp_message.go
│       ├── tcp_packet.go
│       └── tcp_test.go
├── k8s/
│   ├── README.md
│   ├── clusterrole.yaml
│   ├── collect_goreplay_telemetry.sh
│   ├── goreplay.yaml
│   ├── nginx.yaml
│   └── rolebinding.yaml
├── kafka.go
├── limiter.go
├── limiter_test.go
├── middleware/
│   ├── README.md
│   ├── middleware.js
│   └── package.json
├── middleware.go
├── middleware_test.go
├── mkdocs.yml
├── nfpm.yaml
├── output_binary.go
├── output_binary_pro.go
├── output_dummy.go
├── output_file.go
├── output_file_test.go
├── output_http.go
├── output_http_test.go
├── output_kafka.go
├── output_kafka_test.go
├── output_null.go
├── output_s3.go
├── output_s3_pro.go
├── output_tcp.go
├── output_tcp_test.go
├── output_ws.go
├── output_ws_test.go
├── plugins.go
├── plugins_test.go
├── pro.go
├── proto/
│   ├── fuzz.go
│   ├── proto.go
│   └── proto_test.go
├── protocol.go
├── s3/
│   └── index.html
├── s3_reader.go
├── s3_test.go
├── settings.go
├── settings_test.go
├── sidenav.css
├── site/
│   ├── .gitignore
│   ├── Gemfile
│   ├── _config.yml
│   ├── _posts/
│   │   └── 2017-01-06-welcome-to-jekyll.markdown
│   ├── about.md
│   └── index.md
├── snapcraft.yaml
├── tcp_client.go
├── test_input.go
├── test_output.go
└── version.go

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

================================================
FILE: .clabot
================================================
{
  "contributors": ["buger"]
}


================================================
FILE: .deepsource.toml
================================================
version = 1

exclude_patterns = [
  "vendor/**"
]

[[analyzers]]
name = "go"
enabled = true

  [analyzers.meta]
  import_paths = ["github.com/ankitdobhal/goreplay"]

[[analyzers]]
name = "docker"
enabled = true

[[analyzers]]
name = "ruby"
enabled = true

[[analyzers]]
name = "javascript"
enabled = true

  [analyzers.meta]
  environment = ["nodejs"]



================================================
FILE: .dockerignore
================================================
*.tar.gz
gor
gor.test


================================================
FILE: .github/dependabot.yaml
================================================
version: 2
updates:
  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
    pull-request-branch-name:
      # Separate sections of the branch name with a hyphen
      separator: "-"

  - package-ecosystem: "gomod"
    directory: "/"
    schedule:
      interval: "weekly"
      
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
      


================================================
FILE: .github/workflows/ci-docker.yaml
================================================
name: ci
on:
  release:
    types: [published]
jobs:
  docker-build-and-push:
    runs-on: ubuntu-latest
    steps:
      -
        name: "Checkout repository"
        uses: actions/checkout@v3
      -
        name: "Set up Docker Buildx"
        uses: docker/setup-buildx-action@v2
      -
        name: "Cache Docker layers"
        uses: actions/cache@v3.0.5
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-
      -
        name: "Login to Container Registry"
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      -
        name: "Build and push docker image"
        uses: docker/build-push-action@v3
        with:
          context: .
          push: true
          tags: ${{ github.repository }}:${{ github.event.release.tag_name }}
          build-args: RELEASE_VERSION=${{ github.event.release.tag_name }}
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,mode=max,dest=/tmp/.buildx-cache


================================================
FILE: .github/workflows/ci-test.yaml
================================================
name: test
on: [push, pull_request]
jobs:
  test:
    strategy:
      matrix:
        go-version: [1.18.x, 1.19.x] # two latest minor versions
    runs-on: ubuntu-latest
    steps:
    - name: update package index
      run: sudo apt-get update
    - name: install libpcap
      run: sudo apt-get install libpcap-dev -y
    - name: install Go
      uses: actions/setup-go@v2
      with:
        go-version: ${{ matrix.go-version }}
    - name: checkout code
      uses: actions/checkout@v3
    - uses: actions/cache@v3.0.5
      with:
        path: |
          ~/go/pkg/mod              # Module download cache
          ~/.cache/go-build         # Build cache (Linux)
        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
        restore-keys: |
          ${{ runner.os }}-go-
    - name: test
      run: sudo go test ./... -v -timeout 120s


================================================
FILE: .github/workflows/codesee-arch-diagram.yml
================================================
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
  push:
    branches:
      - master
  pull_request_target:
    types: [opened, synchronize, reopened]

name: CodeSee

permissions: read-all

jobs:
  codesee:
    runs-on: ubuntu-latest
    continue-on-error: true
    name: Analyze the repo with CodeSee
    steps:
      - uses: Codesee-io/codesee-action@v2
        with:
          codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
          codesee-url: https://app.codesee.io


================================================
FILE: .github/workflows/probe.yaml
================================================
name: AI Comment Handler


on:
  pull_request:
    types: [opened] #[opened , labeled]
  issue_comment:
    types: [created]          
  issues:
    types: [opened] #[opened, labeled]  
    
# Define permissions needed for the workflow
permissions:
  issues: write
  pull-requests: write
  contents: read

jobs:
  trigger_probe_chat:
    # Uncomment if you want to run on on specific lables, in this example `probe`
    # if: |
    #   (github.event_name == 'pull_request' && github.event.action == 'opened') || 
    #   (github.event_name == 'issues' && github.event.action == 'opened') || 
    #   (github.event_name == 'issue_comment' && github.event.action == 'created') || 
    #   ((github.event_name == 'pull_request' || github.event_name == 'issues') && 
    #    github.event.action == 'labeled' && github.event.label.name == 'probe')
    # Use the reusable workflow from your repository (replace <your-org/repo> and <ref>)
    uses: buger/probe/.github/workflows/probe.yml@main
    # Pass required inputs
    with:
      command_prefix: "/probe" # Or '/ai', '/ask', etc.
      # Optionally override the default npx command if the secret isn't set
      # default_probe_chat_command: 'node path/to/custom/script.js'
    # Pass ALL secrets from this repository to the reusable workflow
    # This includes GITHUB_TOKEN, PROBE_CHAT_COMMAND (if set), ANTHROPIC_API_KEY, etc.
    secrets:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_URL: ${{ secrets.ANTHROPIC_API_URL }}


================================================
FILE: .github/workflows/semgrep.yml
================================================
on:
  pull_request: {}
  push:
    branches:
    - main
    - master
    paths:
    - .github/workflows/semgrep.yml
  schedule:
  # random HH:MM to avoid a load spike on GitHub Actions at 00:00
  - cron: 53 23 * * *
name: Semgrep
jobs:
  semgrep:
    name: Scan
    runs-on: ubuntu-20.04
    env:
      SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
    container:
      image: returntocorp/semgrep
    steps:
    - uses: actions/checkout@v3
    - run: semgrep ci


================================================
FILE: .gitignore
================================================
vendor
*.swp
*.gor
*.rpm
*.dep
*.deb
*.pkg
*.exe
*.pprof
*.out
hey

*.bin
lib/
output/
*.gz
*.zip
.aider*

*.class

*.test
.idea
*.iml
gor

*.mprof

*.pcap

.DS_Store

goreplay
corpus
crashers
suppressions
dist


================================================
FILE: .gitmodules
================================================


================================================
FILE: .request
================================================
POST /post HTTP/1.1
Content-Length: 7
Host: www.w3.org

a=1&b=2


================================================
FILE: COMM-LICENSE
================================================
END-USER LICENSE AGREEMENT

------------------------------------------------------------------------------

IMPORTANT: THIS SOFTWARE END-USER LICENSE AGREEMENT ("EULA") IS A LEGAL AGREEMENT (“Agreement”) BETWEEN YOU (THE CUSTOMER, EITHER AS AN INDIVIDUAL OR, IF PURCHASED OR OTHERWISE ACQUIRED BY OR FOR AN ENTITY, AS AN ENTITY), hereafter "Customer", AND Replay Software LLC ("Licensor"). READ IT CAREFULLY BEFORE COMPLETING THE INSTALLATION PROCESS AND USING GOREPLAY PRO AND RELATED SOFTWARE COMPONENTS (“SOFTWARE”). IT PROVIDES A LICENSE TO USE THE SOFTWARE AND CONTAINS WARRANTY INFORMATION AND LIABILITY DISCLAIMERS. BY INSTALLING AND USING THE SOFTWARE, YOU ARE CONFIRMING YOUR ACCEPTANCE OF THE SOFTWARE AND AGREEING TO BECOME BOUND BY THE TERMS OF THIS AGREEMENT.

------------------------------------------------------------------------------

In order to use the Software under this Agreement, you must receive a “Source URL” at the time of purchase, in accordance with the scope of use and other terms specified for each type of Software and as set forth in this Section 1 of this Agreement. 

1. License Grant

1.1 General Use. This Agreement grants you a non-exclusive, non-transferable, limited license to the use rights for the Software, without the right to grant sublicenses, subject to the terms and conditions in this Agreement. The Software is licensed, not sold.

1.2 Unlimited Organization License. If you purchased an Organization License (included with the GoReplay Pro Software), you may install the Software on an unlimited number of Hosts. “Host” means any physical or virtual machine which is controlled by you. You may concurrently run the software on an unlimited number of Hosts.

1.3 Appliance License. If you purchased an Appliance License, you may distribute the Software in any applications, frameworks, or elements (collectively referred to as an “Application” or “Applications”) that you develop using the Software in accordance with this EULA, provided that such distribution does not violate the restrictions set forth in section 3 of this EULA. You must not remove, obscure or interfere with any copyright, acknowledgment, attribution, trademark, warning or disclaimer statement affixed to, incorporated in or otherwise applied in connection with the Software. You are required to ensure that the Software is not reused by or with any applications other than those with which you distribute it as permitted herein. For example, if You install the Software on a customer’s server, that customer is not permitted to use the Software independently of your Application. You must inform Licensor of your knowledge of any infringing use of the Software by any of your customers. You are liable for compliance by those third parties with the terms and conditions of this EULA. You will not owe Licensor any royalties for your distribution of the Software in accordance with this EULA.

1.4 Archive Copies. You are entitled to make a reasonable amount of copies of the Software for archival purposes. Each copy must reproduce all copyright and other proprietary rights notices on or in the Software Product.

1.5 Electronic Delivery. All Software and license documentation shall be delivered by electronic means unless otherwise specified on the applicable invoice or at the time of purchase. Software shall be deemed delivered when it is made available for download by you (“Delivery”).        

2. Modifications. Licensor shall provide you with source code so that you can create Modifications of the original software. “Modification” means: (a) any addition to or deletion from the contents of a file included in the original Software or previous Modifications created by You, or (b) any new file that contains any part of the original Software or previous Modifications. While you retain all rights to any original work authored by you as part of the Modifications, We continue to own all copyright and other intellectual property rights in the Software.

3. Restricted Uses. 

3.1 You shall not (and shall not allow any third party to): (a) decompile, disassemble, or otherwise reverse engineer the Software or attempt to reconstruct or discover any source code, underlying ideas, algorithms, file formats or programming interfaces of the Software by any means whatsoever (except and only to the extent that applicable law prohibits or restricts reverse engineering restrictions); (b) distribute, sell, sublicense, rent, lease or use the Software for time sharing, hosting, service provider or like purposes, except as expressly permitted under this Agreement; (c) redistribute the Software or Modifications other than by including the Software or a portion thereof within your own product, which must have substantially different functionality than the Software or Modifications and must not allow any third party to use the Software or Modifications, or any portions thereof, for software development or application development purposes; (d) redistribute the Software as part of a product, "appliance" or "virtual server"; (e) redistribute the Software on any server which is not directly under your control; (f) remove any product identification, proprietary, copyright or other notices contained in the Software; (g) modify any part of the Software, create a derivative work of any part of the Software (except as permitted in Section 4), or incorporate the Software, except to the extent expressly authorized in writing by Licensor; (h) publicly disseminate performance information or analysis (including, without limitation, benchmarks) from any source relating to the Software; (i) utilize any equipment, device, software, or other means designed to circumvent or remove any form of Source URL or copy protection used by Licensor in connection with the Software, or use the Software together with any authorization code, Source URL, serial number, or other copy protection device not supplied by Licensor; (j) use the Software to develop a product which is competitive with any Licensor product offerings; or (k) use unauthorized Source URLS or keycode(s) or distribute or publish Source URLs or keycode(s), except as may be expressly permitted by Licensor in writing. If your unique Source URL is ever published, Licensor reserves the right to terminate your access without notice.

3.2 UNDER NO CIRCUMSTANCES MAY YOU USE THE SOFTWARE AS PART OF A PRODUCT OR SERVICE THAT PROVIDES SIMILAR FUNCTIONALITY TO THE SOFTWARE ITSELF.

The Open Source version of the Software (“LGPL Version”) is licensed
under the terms of the GNU Lesser General Public License versions 3.0
(“LGPL”) and not under this EULA. 

4. Ownership. Notwithstanding anything to the contrary contained herein, except for the limited license rights expressly provided herein, Licensor and its suppliers have and will retain all rights, title and interest (including, without limitation, all patent, copyright, trademark, trade secret and other intellectual property rights) in and to the Software and all copies, modifications and derivative works thereof (including any changes which incorporate any of your ideas, feedback or suggestions). You acknowledge that you are obtaining only a limited license right to the Software, and that irrespective of any use of the words “purchase”, “sale” or like terms hereunder no ownership rights are being conveyed to you under this Agreement or otherwise. 

5. Fees and Payment. The Software license fees will be due and payable in full as set forth in the applicable invoice or at the time of purchase. If the Software does not function properly within two weeks of purchase, please contact us within those two weeks for a refund. You shall be responsible for all taxes, withholdings, duties and levies arising from the order (excluding taxes based on the net income of Licensor). 

6. Support, Maintenance and Services. Subject to the terms and conditions of this Agreement, as set forth in your invoice, and as set forth on the GoReplay Pro support page (https://github.com/buger/goreplay/wiki/Pro-Support), support and maintenance services may be included with the purchase of your license subscription.

7. Term of Agreement. 

7.1 Term. This Agreement is effective as of the Delivery of the Software and expires at such time as all license and service subscriptions hereunder have expired in accordance with their own terms (the “Term”). For clarification, the term of your license under this Agreement may be perpetual, limited for Evaluation Version, or designated as a fixed-term license in the Invoice, and shall be specified at your time of purchase. Either party may terminate this Agreement (including all related Invoices) if the other party: (a) fails to cure any material breach of this Agreement within thirty (30) days after written notice of such breach, provided that Licensor may terminate this Agreement immediately upon any breach of Section 3 or if you exceed any other restrictions contained in Section 1, unless otherwise specified in this agreement; (b) ceases operation without a successor; or (c) seeks protection under any bankruptcy, receivership, trust deed, creditors arrangement, composition or comparable proceeding, or if any such proceeding is instituted against such party (and not dismissed within sixty (60) days)). Termination is not an exclusive remedy and the exercise by either party of any remedy under this Agreement will be without prejudice to any other remedies it may have under this Agreement, by law, or otherwise.        

7.2 Termination. Upon any termination of this Agreement, you shall cease any and all use of any Software and destroy all copies thereof. 

7.3 Expiration of License. Upon the expiration of any term under this Agreement, (a) all Software updates and services pursuant to the license shall cease, (b) you may only continue to run existing installations of the Software, (c) you may not install the Software on any additional Hosts, and (d) any new installation of the Software shall require the purchase of a new license subscription from Licensor.

8. Disclaimer of Warranties. The Software is provided "as is," with all faults, defects and errors, and without warranty of any kind. Licensor does not warrant that the Software will be free of bugs, errors, viruses or other defects, and Licensor shall have no liability of any kind for the use of or inability to use the Software, the Software content or any associated service, and you acknowledge that it is not technically practicable for Licensor to do so. 
To the maximum extent permitted by applicable law, Licensor disclaims all warranties, express, implied, arising by law or otherwise, regarding the Software, the Software content and their respective performance or suitability for your intended use, including without limitation any implied warranty of merchantability, fitness for a particular purpose.
Notwithstanding the foregoing, Licensor represents and warrants that it either owns the entire right to, title to, interest in, or has the right to license, the Software, and your proper use of the same will not violate any intellectual property or proprietary rights of another.

9. Limitation of Liability. 

In no event will either party be liable for any direct, indirect, consequential, incidental, special, exemplary, or punitive damages or liabilities whatsoever arising from or relating to the Software, the Software content or this Agreement, whether based on contract, tort (including negligence), strict liability or other theory, even if such party has been advised of the possibility of such damages. Except for indemnification obligations in Section 13.5, in no event will Licensor liability exceed the Software license price as indicated in the invoice. The existence of more than one claim will not enlarge or extend this limit.

10. Remedies. Your exclusive remedy and Licensor’ entire liability for breach of this Agreement shall be limited, at Licensor’ sole and exclusive discretion, to (a) replacement of any defective software or documentation; or (b) refund of the license fee paid to Licensor, payable in accordance with Licensor' refund policy.

11. Acknowledgements.

11.1 Consent to the Use of Data. You agree that Licensor and its affiliates may collect and use technical information gathered as part of the product support services to be used in an anonymized manner. Licensor may use this information solely to improve products and services and will not disclose this information in a form that personally identifies you.

11.2 Verification. We or a certified auditor acting on our behalf, may, upon its reasonable request and at its expense, audit you with respect to the use of the Software, subject to your reasonable information security and confidentiality protections. Such audit may be conducted by mail, electronic means or through an in-person visit to your place of business. Any such in-person audit shall be conducted during regular business hours at your facilities and shall not unreasonably interfere with your business activities. We shall not remove, copy, or redistribute any electronic material during the course of an audit. If an audit reveals that you are using the Software in a way that is in material violation of the terms of the EULA, then you shall pay our reasonable costs of conducting the audit. In the case of a material violation, you agree to pay Us any amounts owing that are attributable to the unauthorized use. In the alternative, We reserve the right, at our sole option, to terminate the licenses for the Software.

11.3 Government End Users. If the Software and related documentation are supplied to or purchased by or on behalf of the United States Government, then the Software is deemed to be "commercial software" as that term is used in the Federal Acquisition Regulation system. Rights of the United States shall not exceed the minimum rights set forth in FAR 52.227-19 for "restricted computer software". All other terms and conditions of this Agreement apply.

12. Third Party Software.  Examples included in Software may provide links to third party libraries or code (collectively “Third Party Software”) to implement various functions. Third Party Software does not comprise part of the Software. In some cases, access to Third Party Software may be included along with the Software delivery as a convenience for demonstration purposes. Such source code and libraries may be included in the “…/examples” source tree delivered with the Software and do not comprise the Software. Licensee acknowledges (1) that some part of Third Party Software may require additional licensing of copyright and patents from the owners of such, and (2) that distribution of any of the Software referencing or including any portion of a Third Party Software may require appropriate licensing from such third parties.


13. Miscellaneous

13.1 Entire Agreement. This Agreement sets forth our entire agreement with respect to the Software and the subject matter hereof and supersedes all prior and contemporaneous understandings and agreements whether written or oral.

13.2 Amendment. Licensor reserves the right, in its sole discretion, to amend this Agreement from time. Amendments to this Agreement can be located at: https://github.com/buger/goreplay/blob/master/COMM-LICENSE.

13.3 Assignment. You may not assign this Agreement or any of its rights under this Agreement without the prior written consent of Licensor and any attempted assignment without such consent shall be void.

13.4 Export Compliance. Each party agrees to comply with all applicable laws and regulations, including laws, regulations, orders or other restrictions on export, re-export or redistribution of software.

13.5 Indemnification. Licensor agrees to defend, indemnify, and hold harmless You from and against any lawsuits, claims, losses, damages, fines and expenses (including attorneys' fees and costs) arising out of a claim brought by a third-party alleging that the Software directly infringes such third-party’s intellectual property rights; provided that Licensor shall have no indemnity obligation for claims arising out of your modification to the Software. You agree to defend, indemnify, and hold harmless Licensor from and against any lawsuits, claims, losses, damages, fines and expenses (including attorneys' fees and costs) brought by a third-party arising out of your modifications to the Software or breach of this Agreement.

13.6 Governing Law. This Agreement is governed by the laws of the State of Oregon and the United States without regard to conflicts of laws provisions thereof, and without regard to the United Nations Convention on the International Sale of Goods or the Uniform Computer Information Transactions Act, as currently enacted by any jurisdiction or as may be codified or amended from time to time by any jurisdiction. The jurisdiction and venue for actions related to the subject matter hereof shall be the state of Oregon and United States federal courts located in Portland, Oregon, and both parties hereby submit to the personal jurisdiction of such courts. 

13.7 Attorneys’ Fees and Costs. The prevailing party in any action to enforce this Agreement will be entitled to recover its attorneys’ fees and costs in connection with such action. 

13.8 Severability. If any provision of this Agreement is held by a court of competent jurisdiction to be invalid, illegal, or unenforceable, the remainder of this Agreement will remain in full force and effect.

13.9 Waiver. Failure or neglect by either party to enforce at any time any of the provisions of this licence Agreement shall not be construed or deemed to be a waiver of that party's rights under this Agreement.

13.10 Headings. The headings of sections and paragraphs of this Agreement are for convenience of reference only and are not intended to restrict, affect or be of any weight in the interpretation or construction of the provisions of such sections or paragraphs.

14. Contact Information. If you have any questions about this EULA, or if you want to contact Licensor for any reason, please direct correspondence to hello@goreplay.org


================================================
FILE: Dockerfile
================================================
FROM alpine:3.16 as builder

ARG RELEASE_VERSION

RUN apk add --no-cache ca-certificates openssl
RUN wget https://github.com/buger/goreplay/releases/download/${RELEASE_VERSION}/gor_${RELEASE_VERSION}_x64.tar.gz -O gor.tar.gz
RUN tar xzf gor.tar.gz

FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /gor .
ENTRYPOINT ["./gor"]


================================================
FILE: Dockerfile.dev
================================================
ARG BASE_IMAGE
FROM ${BASE_IMAGE}

RUN apk add --no-cache \
    gcc \
    g++ \
    make \
    linux-headers \
    bison \
    flex \
    git \
    wget

RUN wget http://www.tcpdump.org/release/libpcap-1.10.0.tar.gz && tar xzf libpcap-1.10.0.tar.gz && cd libpcap-1.10.0 && ./configure && make install

WORKDIR /go/src/github.com/buger/goreplay/
ADD . /go/src/github.com/buger/goreplay/

RUN go get golang.org/x/lint/golint
RUN go get


================================================
FILE: ELASTICSEARCH.md
================================================
gor & elasticsearch
===================

Prerequisites
-------------

- elasticsearch
- kibana (Get it here: http://www.elasticsearch.org/overview/kibana/)
- gor


elasticsearch
-------------

The default elasticsearch configuration is just fine for most workloads. You won't need clustering, sharding or something like that.

In this example we're installing it on our gor replay server which gives us the elasticsearch listener on _http://localhost:9200_


kibana
------

Kibana (elasticsearch analytics web-ui) is just as simple. 
Download it, extract it and serve it via a simple webserver.
(Could be nginx or apache)

You could also use a shell, ```cd``` into the kibana directory and start a little quick and dirty python webserver with:

```
python -m SimpleHTTPServer 8000
```

In this example we're also choosing the gor replay server as our kibana host. If you choose a different server you'll have to point kibana to your elasticsearch host.


gor
---

Start your gor replay server with elasticsearch option:

```
./gor --input-raw :8000 --output-http http://staging.com  --output-http-elasticsearch localhost:9200/gor
```


(You don't have to create the index upfront. That will be done for you automatically)


Now visit your kibana url, load the predefined dashboard from the gist https://gist.github.com/gottwald/b2c875037f24719a9616 and watch the data rush in.


Troubleshooting
---------------

The replay process may complain about __too many open files__.
That's because your typical linux shell has a small open files soft limit at 1024.
You can easily raise that when you do this before starting your _gor replay_ process:

```
ulimit -n 64000
```

Please be aware, this is not a permanent setting. It's just valid for the following jobs you start from that shell.

We reached the 1024 limit in our tests with a ubuntu box replaying about 9000 requests per minute. (We had very slow responses there, should be way more with fast responses)


================================================
FILE: LICENSE.txt
================================================
Copyright (c) 2011-present Leonid Bugaev

Portions of this software are licensed as follows:

* All content residing under the "doc/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
* The file "pro.go" and all files ending with the "_pro.go" suffix are released under the commercial license specified in the "COMM-LICENSE" file.
* Content outside of the above mentioned directories or restrictions above is available under the "LGPLv3" license as defined below.


GoReplay is an Open Source project licensed under the terms of
the LGPLv3 license.  Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
for license text.

As a special exception to the GNU Lesser General Public License version 3
("LGPL3"), the copyright holders of this Library give you permission to
convey to a third party a Combined Work that links statically or dynamically
to this Library without providing any Minimal Corresponding Source or
Minimal Application Code as set out in 4d or providing the installation
information set out in section 4e, provided that you comply with the other
provisions of LGPL3 and provided that you meet, for the Application the
terms and conditions of the license(s) which apply to the Application.

TLDR: You are free to use Gor subpackages like `byteutils` or `proto` in your commercial projects.


GoReplay Pro has a commercial-friendly license allowing private forks
and modifications of GoReplay.  Please see https://goreplay.org/pro.html for
more detail.  You can find the commercial license terms in COMM-LICENSE.


================================================
FILE: Makefile
================================================
SOURCE = $(shell ls -1 *.go | grep -v _test.go)
PROJECT_NAME := goreplay
SOURCE_PATH = /go/src/github.com/buger/goreplay/
PORT = 8000
FADDR = :8000
DIST_PATH = dist
CONTAINER_AMD=gor-amd64
CONTAINER_ARM=gor-arm64
RUN = docker run --rm -v `pwd`:$(SOURCE_PATH) -e AWS_ACCESS_KEY_ID=$(AWS_ACCESS_KEY_ID) -e AWS_SECRET_ACCESS_KEY=$(AWS_SECRET_ACCESS_KEY) -p 0.0.0.0:$(PORT):$(PORT) -t -i $(CONTAINER_AMD)
BENCHMARK = BenchmarkRAWInput
TEST = TestRawListenerBench
BIN_NAME = gor
VERSION := DEV-$(shell date +%s)
CUSTOM_TAGS := --tags "ngo$(if $(CUSTOM_BUILD_TAGS), $(CUSTOM_BUILD_TAGS),)"
LDFLAGS = -ldflags "-X main.VERSION=$(VERSION) -extldflags \"-static\" -X main.DEMO=$(DEMO)"
MAC_LDFLAGS = -ldflags "-X main.VERSION=$(VERSION) -X main.DEMO=$(DEMO)"
DOCKER_FPM_CMD := docker run --rm -t -v `pwd`:/src -w /src fleetdm/fpm

FPM_COMMON= \
				--name $(PROJECT_NAME) \
				--description "GoReplay is an open-source network monitoring tool which can record your live traffic, and use it for shadowing, load testing, monitoring and detailed analysis." \
				-v $(VERSION) \
				--vendor "Leonid Bugaev" \
				-m "<support@goreplay.org>" \
				--url "https://goreplay.org" \
				-s dir

release: clean release-linux-amd64 release-linux-arm64 release-mac-amd64 release-mac-arm64 release-windows

.PHONY: vendor
vendor:
	go mod vendor

release-bin-linux-amd64: vendor
	docker run --platform linux/amd64 --rm -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=amd64 -i $(CONTAINER_AMD) go build -mod=vendor -o $(BIN_NAME) $(CUSTOM_TAGS) $(LDFLAGS) ./cmd/gor/

release-bin-linux-arm64: vendor
	docker run --platform linux/arm64 --rm -v `pwd`:$(SOURCE_PATH) -t --env GOOS=linux --env GOARCH=arm64 -i $(CONTAINER_ARM) go build -mod=vendor -o $(BIN_NAME) $(CUSTOM_TAGS) $(LDFLAGS) ./cmd/gor/

release-bin-mac-amd64: vendor
	GOOS=darwin go build -mod=vendor -o $(BIN_NAME) $(CUSTOM_TAGS) $(MAC_LDFLAGS) ./cmd/gor/

release-bin-mac-arm64: vendor
	GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go build -mod=vendor -o $(BIN_NAME) $(CUSTOM_TAGS) $(MAC_LDFLAGS)

release-bin-windows: vendor
	docker run -it --rm -v `pwd`:$(SOURCE_PATH) -w $(SOURCE_PATH) -e CGO_ENABLED=1 docker.elastic.co/beats-dev/golang-crossbuild:1.19.2-main --build-cmd "make VERSION=$(VERSION) CUSTOM_BUILD_TAGS=$(CUSTOM_BUILD_TAGS) build" -p "windows/amd64" ./cmd/gor/
	mv $(BIN_NAME) "$(BIN_NAME).exe"

release-linux-amd64: dist release-bin-linux-amd64
	tar -czf $(DIST_PATH)/gor_$(VERSION)_linux_amd64.tar.gz $(BIN_NAME)
	$(DOCKER_FPM_CMD) $(FPM_COMMON) -f -t deb -a arm64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	$(DOCKER_FPM_CMD) $(FPM_COMMON) -f -t rpm -a arm64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	rm -rf $(BIN_NAME)

release-linux-arm64: dist release-bin-linux-arm64
	tar -czf $(DIST_PATH)/gor_$(VERSION)_linux_arm64.tar.gz $(BIN_NAME)
	$(DOCKER_FPM_CMD) $(FPM_COMMON) -f -t deb -a arm64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	$(DOCKER_FPM_CMD) $(FPM_COMMON) -f -t rpm -a arm64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	rm -rf $(BIN_NAME)

release-mac-amd64: dist release-bin-mac-amd64
	tar -czf $(DIST_PATH)/gor_$(VERSION)_darwin_amd64.tar.gz $(BIN_NAME)
	fpm $(FPM_COMMON) -f -t osxpkg -a amd64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	mv ./$(DIST_PATH)/$(PROJECT_NAME)-$(VERSION).pkg ./$(DIST_PATH)/$(PROJECT_NAME)-$(VERSION)-amd64.pkg
	rm -rf $(BIN_NAME)

release-mac-arm64: dist release-bin-mac-arm64
	tar -czf $(DIST_PATH)/gor_$(VERSION)_darwin_arm64.tar.gz $(BIN_NAME)
	fpm $(FPM_COMMON) -f -t osxpkg -a arm64 -p ./$(DIST_PATH) ./gor=/usr/local/bin
	mv ./$(DIST_PATH)/$(PROJECT_NAME)-$(VERSION).pkg ./$(DIST_PATH)/$(PROJECT_NAME)-$(VERSION)-arm64.pkg
	rm -rf $(BIN_NAME)

release-windows: dist release-bin-windows
	zip $(DIST_PATH)/gor-$(VERSION)_windows.zip "$(BIN_NAME).exe"
	rm -rf "$(BIN_NAME).exe"

clean:
	rm -rf $(DIST_PATH)

build:
	go build -mod=vendor -o $(BIN_NAME) $(CUSTOM_TAGS) $(LDFLAGS)

install:
	go install $(CUSTOM_TAGS) $(MAC_LDFLAGS)

build-env: build-amd64-env build-arm64-env

build-amd64-env:
	docker buildx build --build-arg BASE_IMAGE=golang:1.22-alpine --platform linux/amd64 -t $(CONTAINER_AMD) -f Dockerfile.dev --load .

build-arm64-env:
	docker buildx build --build-arg BASE_IMAGE=arm64v8/golang:1.22-alpine --platform linux/arm64 -t $(CONTAINER_ARM) -f Dockerfile.dev --load .

build-docker:
	docker build -t gor-dev -f Dockerfile .

profile:
	go build && ./$(BIN_NAME) --output-http="http://localhost:9000" --input-dummy 0 --input-raw :9000 --input-http :9000 --memprofile=./mem.out --cpuprofile=./cpu.out --stats --output-http-stats --output-http-timeout 100ms

lint:
	$(RUN) golint $(PKG)

race:
	$(RUN) go test ./... $(ARGS) -v -race -timeout 15s

test:
	$(RUN) go test ./. -timeout 120s $(CUSTOM_TAGS) $(LDFLAGS) $(ARGS)  -v

test_all:
	$(RUN) go test ./... -timeout 120s $(CUSTOM_TAGS) $(LDFLAGS) $(ARGS) -v

testone:
	$(RUN) go test ./. -timeout 60s $(CUSTOM_TAGS) $(LDFLAGS) -run $(TEST) $(ARGS) -v

cover:
	$(RUN) go test $(ARGS) -race -v -timeout 15s -coverprofile=coverage.out
	go tool cover -html=coverage.out

fmt:
	$(RUN) gofmt -w -s ./..

vet:
	$(RUN) go vet

bench:
	$(RUN) go test $(CUSTOM_TAGS) $(LDFLAGS) -v -run NOT_EXISTING -bench $(BENCHMARK) -benchtime 5s

profile_test:
	$(RUN) go test $(CUSTOM_TAGS) $(LDFLAGS) -run $(TEST) ./capture/. $(ARGS) -memprofile mem.mprof -cpuprofile cpu.out
	$(RUN) go test $(CUSTOM_TAGS) $(LDFLAGS) -run $(TEST) ./capture/. $(ARGS) -c

# Used mainly for debugging, because docker container do not have access to parent machine ports
run:
	$(RUN) go run $(CUSTOM_TAGS) $(LDFLAGS) $(SOURCE) --input-dummy=0 --output-http="http://localhost:9000" --input-raw-track-response --input-raw 127.0.0.1:9000 --verbose 0 --middleware "./examples/middleware/echo.sh" --output-file requests.gor

run-2:
	$(RUN) go run $(CUSTOM_TAGS) $(LDFLAGS) $(SOURCE) --input-raw :8000 --input-raw-bpf-filter "dst port 8000" --output-stdout --output-http "http://localhost:8000" --input-dummy=0

run-3:
	sudo -E go run $(CUSTOM_TAGS) $(SOURCE) --input-tcp :27001 --output-stdout

run-arg:
	sudo -E go run $(CUSTOM_TAGS) $(SOURCE) $(ARGS)

file-server:
	go run $(CUSTOM_TAGS) $(SOURCE) file-server $(FADDR)

readpcap:
	go run $(CUSTOM_TAGS) $(SOURCE) --input-raw $(FILE) --input-raw-track-response --input-raw-engine pcap_file --output-stdout

record:
	$(RUN) go run $(CUSTOM_TAGS) $(SOURCE) --input-dummy=0 --output-file=requests.gor --verbose --debug

replay:
	$(RUN) go run $(CUSTOM_TAGS) $(SOURCE) --input-file=requests.bin --output-tcp=:9000 --verbose -h

bash:
	$(RUN) /bin/bash

dist:
	mkdir -p $(DIST_PATH)


================================================
FILE: Procfile
================================================
web: python -m SimpleHTTPServer 8000
replayed_web: python -m SimpleHTTPServer 8001
listener: sudo -E go run ./bin/gor.go --input-raw :8000 --output-tcp :8002 --verbose
replay: go run ./bin/gor.go --input-tcp :8002 --output-http localhost:8001 --verbose


================================================
FILE: README.md
================================================
<a href="https://semgrep.dev/login?utm_source=github&utm_medium=badge&utm_campaign=growth-oss"><img src="https://img.shields.io/badge/semgrep-security-green.svg" /></a> [![GitHub release](https://img.shields.io/github/release/buger/gor.svg?maxAge=3600)](https://github.com/buger/goreplay/releases) [![codebeat](https://codebeat.co/badges/6427d589-a78e-416c-a546-d299b4089893)](https://codebeat.co/projects/github-com-buger-gor) [![Go Report Card](https://goreportcard.com/badge/github.com/buger/gor)](https://goreportcard.com/report/github.com/buger/gor) [![Join the chat at https://gitter.im/buger/gor](https://badges.gitter.im/buger/gor.svg)](https://gitter.im/buger/gor?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)

![Go Replay](http://i.imgur.com/ZG2ki5n.png)

## https://goreplay.org/

GoReplay is an open-source network monitoring tool which can record your live traffic and use it for shadowing, load testing, monitoring and detailed analysis.

## About

As your application grows, the effort required to test it also grows exponentially. GoReplay offers you the simple idea of reusing your existing traffic for testing, which makes it incredibly powerful. Our state of art technique allows you to analyze and record your application traffic without affecting it. This eliminates the risks that come with putting a third party component in the critical path. 

GoReplay increases your confidence in code deployments, configuration and infrastructure changes.


GoReplay offers a unique approach for shadowing. Instead of being a proxy, GoReplay listens in the background for traffic on your network interfaces, requiring no changes in your production infrastructure, other than running GoReplay daemon on the same machine as your service.

![Diagram](https://i.imgur.com/IN2xfDm.png)

Check [latest documentation](http://github.com/buger/goreplay/wiki).

## Installation
Download the latest binary from https://github.com/buger/goreplay/releases or [compile by yourself](https://github.com/buger/goreplay/wiki/Compilation).

## Getting started

The most basic setup will be `sudo ./gor --input-raw :8000 --output-stdout` which acts like tcpdump.
If you already have a test environment, you can start replaying by running: `sudo ./gor --input-raw :8000 --output-http http://staging.env`.

See our [documentation](https://github.com/buger/goreplay/wiki/) and the [Getting Started](https://github.com/buger/goreplay/wiki/Getting-Started) page for more info. 

## Newsletter
Subscribe to our [newsletter](https://www.getdrip.com/forms/89690474/submissions/new) to stay informed about the latest features and changes to the Gor project.

## Want to Upgrade?

We have created a [GoReplay PRO](https://goreplay.org/pro.html) extension which provides additional features such as support for binary protocols like Thrift or ProtocolBuffers, saving and replaying from cloud storage, TCP session replication, etc. The PRO version also includes a commercial-friendly license, dedicated support, and it also allows you to support high-quality open source development. 


## Problems?
If you have a problem, please review the [FAQ](https://github.com/buger/goreplay/wiki/FAQ) and [Troubleshooting](https://github.com/buger/goreplay/wiki/Troubleshooting) wiki pages. Searching the [issues](https://github.com/buger/goreplay/issues) for your problem is also a good idea.

All bug-reports and suggestions should go through Github Issues or our [Google Group](https://groups.google.com/forum/#!forum/gor-users) (you can just send email to gor-users@googlegroups.com).
If you have a private question feel free to send email to support@gortool.com.


## Contributing

1. Fork it
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Added some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create new Pull Request

## Companies using Gor

* [GOV.UK](https://www.gov.uk) - UK Government Digital Service
* [theguardian.com](http://theguardian.com) - Most popular online newspaper in the UK
* [TomTom](http://www.tomtom.com/) - Global leader in navigation, traffic and map products, GPS Sport Watches and fleet management solutions.
* [3SCALE](http://www.3scale.net/) - API infrastructure to manage your APIs for internal or external users
* [Optionlab](http://www.opinionlab.com) - Optimize customer experience and drive engagement across multiple channels
* [TubeMogul](http://tubemogul.com) - Software for Brand Advertising
* [Videology](http://www.videologygroup.com/) - Video advertising platform
* [ForeksMobile](http://foreksmobile.com/) -  One of the leading financial application development company in Turkey
* [Granify](http://granify.com) - AI backed SaaS solution that enables online retailers to maximise their sales
* And many more!

If you are using Gor, we are happy to add you to the list and share your story, just write to: hello@goreplay.org

## Author

Leonid Bugaev, [@buger](https://twitter.com/buger), https://leonsbox.com


================================================
FILE: ce.go
================================================
//go:build !pro

package goreplay

import (
	"fmt"
)

// PRO this value indicates if goreplay is running in PRO mode.
var PRO = false

func SettingsHook(settings *AppSettings) {
	if settings.RecognizeTCPSessions {
		settings.RecognizeTCPSessions = false
		fmt.Println("[ERROR] TCP session recognition is not supported in the open-source version of GoReplay")
	}
}


================================================
FILE: circle.yml
================================================
dependencies:
  pre:
    - sudo apt-get install libpcap-dev -y

test:
  override:
    - sudo bash -l -c "export GOPATH='/home/ubuntu/.go_workspace:/usr/local/go_workspace:/home/ubuntu/.go_project' && GORACE='halt_on_error=1' /usr/local/go/bin/go test ./... -v -timeout 120s -race"

================================================
FILE: docs/CNAME
================================================
docs.goreplay.org

================================================
FILE: docs/Capturing-and-replaying-traffic.md
================================================
Think about Gor more like a network analyzer or tcpdump on steroids, it is not a proxy and does not affect your app anyhow. You specify application port, and it will capture and replay incoming data.

Simplest setup will be:
```bash
# Run on servers where you want to catch traffic. You can run it on every `web` machine.
sudo gor --input-raw :80 --output-http http://staging.com
```
It will record and replay traffic from the same machine. However, it is possible to use [[Aggregator-forwarder setup]], when Gor on your web machines forward traffic to Gor aggregator instance running on the separate server.

> You may notice that it require `sudo`: to analyze network Gor need permissions which available only to root users. However, it is possible to configure Gor [beign run for non-root users](Running as a non-root user).


### Forwarding to multiple addresses

You can forward traffic to multiple endpoints.
```
gor --input-tcp :28020 --output-http "http://staging.com"  --output-http "http://dev.com"
```

### Splitting traffic
By default, it will send same traffic to all outputs, but you have options to equally split it (round-robin) using  `--split-output` option.

```
gor --input-raw :80 --output-http "http://staging.com"  --output-http "http://dev.com" --split-output true
```

### Tracking responses
By default `input-raw` does not intercept responses, only requests. You can turn response tracking using `--input-raw-track-response` option. When enable you will be able to access response information in middleware and `output-file`.


### Traffic interception engine
By default, Gor will use `libpcap` for intercepting traffic, it should work in most cases. If you have any troubles with it, you may try alternative engine: `raw_socket`.

```
sudo gor --input-raw :80 --input-raw-engine "raw_socket" --output-http "http://staging.com"
```

You can read more about [[Replaying HTTP traffic]].

You can use VXLAN or traffic mirroring from AWS to capture the traffic. The 4789 UDP port will be opened and that works as you are launched GoReplay on the source machine.

```
gor --input-raw :80 --input-raw-engine vxlan -output-stdout
```

### Tracking original IP addresses
You can use `--input-raw-realip-header` option to specify header name: If not blank, injects header with given name and real IP value to the request payload. Usually, this header should be named: `X-Real-IP`, but you can specify any name.

`gor --input-raw :80 --input-raw-realip-header "X-Real-IP" ...`


***

Also you may want to know about [[Rate limiting]], [[Request rewriting]] and [[Request filtering]]

================================================
FILE: docs/Compilation.md
================================================
We provide pre-compiled binaries for Mac and Linux, but you are free to compile Gor by yourself.

Gor is written using Go, so first you need to download it from here https://golang.org/, use the latest stable version. 

The only Gor dependency is [libpcap](https://github.com/the-tcpdump-group/libpcap), which is the interface to various kernel packet capture mechanisms, and https://github.com/google/gopacket, which is a Go wrapper around libpcap. Latest libpcap version can be obtained at http://www.tcpdump.org/release/. Libpcap itself depend on `flex` and `bison` packages, many operating systems already have them installed.

```bash
# Fetch libpcap dependencies. Depending on your OS, instead of `apt` you will use `yum` or `rpm`, or `brew` on Mac.
sudo apt-get install flex bison -y

# Download latest stable release, compile and install it
wget http://www.tcpdump.org/release/libpcap-1.7.4.tar.gz && tar xzf libpcap-1.7.4.tar.gz
cd libpcap-1.7.4
./configure && make install


# Lets fetch Gor source code
mkdir $HOME/gocode
# See more information about GOPATH https://github.com/golang/go/wiki/GOPATH
export GOPATH=$HOME/gocode
# Fetch code from the Github
go get github.com/buger/gor

# Compile from source
cd $HOME/gocode/src/github.com/buger/gor
go build LDFLAGS = -ldflags "-extldflags \"-static\""
```

After you finished, you should see `gor` binary in current directory. 



================================================
FILE: docs/Development-Setup.md
================================================
## STEP 1: Install Docker
For local development we recommend to use Docker.

If you don’t have it you can read how to install it here:
https://docs.docker.com/engine/getstarted/step_one/#step-3-verify-your-installation

## STEP 2: Download repository

`git clone git@github.com:buger/goreplay.git`


## STEP 3: Setup container

```
cd ./goreplay
make build

```

## Testing
To run tests execute next command:

```
make test
```

You can copy the command that is produced and modify it. For example, if you need to run one test copy the command and add `-run TestName`, e.g.:

```
docker run -v `pwd`:/go/src/github.com/buger/gor/ -p 0.0.0.0:8000:8000 -t -i gor:go go test ./. -run TestEmitterFiltered -timeout 60s -ldflags "-X main.VERSION=DEV-1482398347 -extldflags \"-static\""   -v
```


## Building
To get a binary file run 

```
make release-bin
```


================================================
FILE: docs/Distributed-configuration.md
================================================
Sometimes it makes sense to use separate Gor instance for replaying traffic and performing things like load testing, so your production machines do not spend precious resources. It is possible to configure Gor on your web machines forward traffic to Gor aggregator instance running on the separate server.

```bash
# Run on servers where you want to catch traffic. You can run it on each `web` machine.
sudo gor --input-raw :80 --output-tcp replay.local:28020

# Replay server (replay.local).
gor --input-tcp replay.local:28020 --output-http http://staging.com
```

If you have multiple replay machines you can split traffic among them using `--split-output` option: it will equally split all incoming traffic to all outputs using round robin algorithm.
```
gor --input-raw :80 --split-output --output-tcp replay1.local:28020 --output-tcp replay2.local:28020
```

[GoReplay PRO](https://goreplay.org/pro.html) support accurate recording and replaying of tcp sessions, and when `--recognize-tcp-sessions` option is passed, instead of round-robin it will use a smarter algorithm which ensures that same sessions will be sent to the same replay instance.


In case if you are planning a large load testing, you may consider use separate master instance which will control Gor slaves which actually replay traffic. For example:
```
# This command will read multiple log files, replay them on 10x speed and loop them if needed for 30 seconds, and will distributed traffic (tcp session aware) among multiple workers
gor --input-file logs_from_multiple_machines.*|1000% --input-file-loop --exit-after 30s --recognize-tcp-sessions --split-output --output-tcp worker1.local --output-tcp worker2.local:27017 --output-tcp worker3.local:27017 ...  --output-tcp workerN.local:27017

# worker 
gor --input-tcp :27017 --ouput-http load_test.target
```


================================================
FILE: docs/Exporting-to-ElasticSearch.md
================================================
Gor can export requests and replayed response data to ElasticSearch:

```
./gor --input-raw :8000 --output-http http://staging.com  --output-http-elasticsearch localhost:9200/gor
```

You don't have to create the index upfront. That will be done for you automatically.

### Format

Following structure represents ES format:

```
type ESRequestResponse struct {
	ReqURL               string `json:"Req_URL"`
	ReqMethod            string `json:"Req_Method"`
	ReqUserAgent         string `json:"Req_User-Agent"`
	ReqAcceptLanguage    string `json:"Req_Accept-Language,omitempty"`
	ReqAccept            string `json:"Req_Accept,omitempty"`
	ReqAcceptEncoding    string `json:"Req_Accept-Encoding,omitempty"`
	ReqIfModifiedSince   string `json:"Req_If-Modified-Since,omitempty"`
	ReqConnection        string `json:"Req_Connection,omitempty"`
	ReqCookies           string `json:"Req_Cookies,omitempty"`
	RespStatus           string `json:"Resp_Status"`
	RespStatusCode       string `json:"Resp_Status-Code"`
	RespProto            string `json:"Resp_Proto,omitempty"`
	RespContentLength    string `json:"Resp_Content-Length,omitempty"`
	RespContentType      string `json:"Resp_Content-Type,omitempty"`
	RespTransferEncoding string `json:"Resp_Transfer-Encoding,omitempty"`
	RespContentEncoding  string `json:"Resp_Content-Encoding,omitempty"`
	RespExpires          string `json:"Resp_Expires,omitempty"`
	RespCacheControl     string `json:"Resp_Cache-Control,omitempty"`
	RespVary             string `json:"Resp_Vary,omitempty"`
	RespSetCookie        string `json:"Resp_Set-Cookie,omitempty"`
	Rtt                  int64  `json:"RTT"`
	Timestamp            time.Time
}
```

================================================
FILE: docs/FAQ.md
================================================
### What OS are supported?
Gor will run everywhere where [libpcap](http://www.tcpdump.org/) works, and it works on most of the platforms. However, currently, we test it on Linux and Mac. See more about [[Compilation]].

### Why does the `--input-raw` requires sudo or root access?
Listener works by sniffing traffic from a given port. It's accessible
only by using sudo or root access. But it is possible to [[Running as non root user]].

### How do you deal with user session to replay the traffic correctly?
You can rewrite session related headers/params to match your staging environment. If you require custom logic (e.g random token based auth) follow this discussion: https://github.com/buger/gor/issues/154

### Can I use Gor to intercept SSL traffic?
Basic idea is that SSL was made to protect itself from traffic interception. There 2 options: 
1. Move SSL handling to proxy like Nginx or Amazon ELB. And allow Gor to listen on upstreams. 
2. Use `--input-http` so you can duplicate request payload directly from your app to Gor, but it will require your app modifications.

More can be find here: https://github.com/buger/gor/issues/85

### Is there a limit for size of HTTP request when using output-http?
Due to the fact that Gor can't guarantee interception of all packets, for large payloads > 200kb there is chance of missing some packets and corrupting body. Treat it as a feature and chance to test broken bodies handling :)
The only way to guarantee delivery is using `--input-http`, but you will miss some features.

### I'm getting 'too many open files' error
Typical Linux shell has a small open files soft limit at 1024. You can easily raise that when you do this before starting your gor replay process:
  
  ulimit -n 64000

More about ulimit: http://www.thecodingmachine.com/solving-the-too-many-open-files-exception-in-red5-or-any-other-application/

### The CPU average across my load-balanced targets is higher than the source
If you are replaying traffic from multiple listeners to a load-balanced target and you use sticky sessions, you may observe that the target servers have a higher CPU load than the listener servers. This may be because the sticky session cookie of the original load balancer is not honored by the target load balancer thus resulting in requests that would normally hit the same target server hitting different servers on the backend thus reducing some caching benefits gained via the load balancing.  Try running just one listener against one replay target and see if the CPU utilization comparison is more accurate.

Also see [[Troubleshooting]].

================================================
FILE: docs/Middleware.md
================================================
#### Overview
Middleware is a program that accepts request and response payload at STDIN and emits modified requests at STDOUT. You can implement any custom logic like stripping private data, advanced rewriting, support for oAuth and etc. Check examples [included into our repo](https://github.com/buger/gor/tree/master/examples/middleware).


```
                   Original request      +--------------+
+-------------+----------STDIN---------->+              |
|  Gor input  |                          |  Middleware  |
+-------------+----------STDIN---------->+              |
                   Original response (1) +------+---+---+
                                                |   ^
+-------------+    Modified request             v   |
| Gor output  +<---------STDOUT-----------------+   |
+-----+-------+                                     |
      |                                             |
      |            Replayed response                |
      +------------------STDIN----------------->----+
```

(1): Original responses will only be sent to the middleware if the `--input-raw-track-response` option is specified.

Middleware can be written in any language, see `examples/middleware` folder for examples.
Middleware program should accept the fact that all communication with Gor is asynchronous, there is no guarantee that original request and response messages will come one after each other. Your app should take care of the state if logic depends on original or replayed response, see `examples/middleware/token_modifier.go` as example.

Simple bash echo middleware (returns same request) will look like this:
```bash
while read line; do
  echo $line
done
```

Middleware can be enabled using `--middleware` option, by specifying path to executable file:
```
gor --input-raw :80 --middleware "/opt/middleware_executable" --output-http "http://staging.server"
```

#### Communication protocol
All messages should be hex encoded, new line character specifieds the end of the message, eg. new message per line.

Decoded payload consist of 2 parts: header and HTTP payload, separated by new line character.  

Example request payload:

```
1 932079936fa4306fc308d67588178d17d823647c 1439818823587396305
GET /a HTTP/1.1
Host: 127.0.0.1

```

Example response payload (note: you will only receive this if you specify `--input-raw-track-response`)

```
2 8e091765ae902fef8a2b7d9dd960e9d52222bd8c 1439818823587996305 2782013
HTTP/1.1 200 OK
Date: Mon, 17 Aug 2015 13:40:23 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

```

Header contains request meta information separated by spaces. First value is payload type, possible values: `1` - request, `2` - original response, `3` - replayed response.
Next goes request id: unique among all requests (sha1 of time and Ack), but remain same for original and replayed response, so you can create associations between request and responses. The third argument is the time when request/response was initiated/received. Forth argument is populated only for responses and means latency.

HTTP payload is unmodified HTTP requests/responses intercepted from network. You can read more about request format [here](http://www.jmarshall.com/easy/http/), [here](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) and [here](http://www.w3.org/Protocols/rfc2616/rfc2616.html). You can operate with payload as you want, add headers, change path, and etc. Basically you just editing a string, just ensure that it is RCF compliant.

At the end modified (or untouched) request should be emitted back to STDOUT, keeping original header, and hex-encoded. If you want to filter request, just not send it. Emitting responses back is required, even if you did not touch them.

#### Advanced example
Imagine that you have auth system that randomly generate access tokens, which used later for accessing secure content. Since there is no pre-defined token value, naive approach without middleware (or if middleware use only request payloads) will fail, because replayed server have own tokens, not synced with origin. To fix this, our middleware should take in account responses of replayed and origin server, store `originalToken -> replayedToken` aliases and rewrite all requests using this token to use replayed alias. See [examples/middleware/token_modifier.go](https://github.com/buger/gor/tree/master/examples/middleware/token_modifier.go) and [middleware_test.go#TestTokenMiddleware](https://github.com/buger/gor/tree/master/middleware_test.go) as example of described scheme.

***

You may also read about [[Request filtering]], [[Rate limiting]] and [[Request rewriting]].


================================================
FILE: docs/Rate-limiting.md
================================================
Rate limiting can be useful if you only want to forward parts of incoming traffic, for example, to not overload your test environment. There are two strategies: dropping random requests or dropping fractions of requests based on Header or URL param value. 

### Dropping random requests
Every input and output support random rate limiting.
There are two limiting algorithms: absolute or percentage based. 

**Absolute**: If for current second it reached specified requests limit - disregard the rest, on next second counter reset.

**Percentage**: For input-file it will slowdown or speedup request execution, for the rest it will use the random generator to decide if request pass or not based on the chance you specified. 

You can specify your desired limit using the "|" operator after the server address, see examples below.

#### Limiting replay using absolute number
```
# staging.server will not get more than ten requests per second
gor --input-tcp :28020 --output-http "http://staging.com|10"
```

#### Limiting listener using percentage based limiter
```
# replay server will not get more than 10% of requests 
# useful for high-load environments
gor --input-raw :80 --output-tcp "replay.local:28020|10%"
```

### Consistent limiting based on Header or URL param value
If you have unique user id (like API key) stored in header or URL you can consistently forward specified percent of traffic only for the fraction of this users. 
Basic formula looks like this: `FNV32-1A_hashing(value) % 100 >= chance`. Examples:
```
# Limit based on header value
gor --input-raw :80 --output-tcp "replay.local:28020|10%" --http-header-limiter "X-API-KEY: 10%"

# Limit based on header value
gor --input-raw :80 --output-tcp "replay.local:28020|10%" --http-param-limiter "api_key: 10%"
```

When limiting based on header or param only percentage based limiting supported.

================================================
FILE: docs/Replaying-HTTP-traffic.md
================================================
Gor can replay HTTP traffic using `--output-http` option:

```bash
sudo ./gor --input-raw :8000 --output-http="http://staging.env"
```

You can [filter](Request filtering), [rate limit](Rate limiting) and [rewrite](Request rewriting) requests on the fly. 

### HTTP output workers
By default Gor creates a dynamic pool of workers: it starts with 10 and creates more HTTP output workers when the HTTP output queue length is greater than 10.  The number of workers created (N) is equal to the queue length at the time which it is checked and found to have a length greater than 10. The queue length is checked every time a message is written to the HTTP output queue.  No more workers will be spawned until that request to spawn N workers is satisfied.  If a dynamic worker cannot process a message at that time, it will sleep for 100 milliseconds. If a dynamic worker cannot process a message for 2 seconds it dies.
You may specify fixed number of workers using  `--output-http-workers=20` option.

### Following redirects
By default Gor will ignore all redirects since they are handled by clients using your app, but in scenarios where your replayed environment introduces new redirects, you can enable them like this: 
```
gor --input-tcp replay.local:28020 --output-http http://staging.com --output-http-redirects 2
```
The given example will follow up to 2 redirects per request.

### HTTP timeouts
By default http timeout for both request and response is 5 seconds. You can override it like this:
```
gor --input-tcp replay.local:28020 --output-http http://staging.com --output-http-timeout 30s
```

### Response buffer
By default, to reduce memory consumption, internal HTTP client will fetch max 200kb of the response body (used if you use middleware), by you can increase limit using `--output-http-response-buffer` option (accepts number of bytes).

### Basic Auth

If your development or staging environment is protected by Basic Authentication then those credentials can be injected in during the replay:

```
gor --input-raw :80 --output-http "http://user:pass@staging.com"
```

Note: This will overwrite any Authorization headers in the original request.


### Multiple domains support

If you app accepts traffic from multiple domains, and you want to keep original headers, there is specific `--http-original-host` with tells Gor do not touch Host header at all.


***
You may also read about [[Saving and Replaying from file]]

================================================
FILE: docs/Request-filtering.md
================================================
Filtering is useful when you need to capture only specific part of traffic, like API requests. It is possible to filter by URL, HTTP header or HTTP method.

#### Allow url regexp
```
# only forward requests being sent to the /api endpoint
gor --input-raw :8080 --output-http staging.com --http-allow-url /api
```

#### Disallow url regexp
```
# only forward requests NOT being sent to the /api... endpoint
gor --input-raw :8080 --output-http staging.com --http-disallow-url /api
```
#### Filter based on regexp of header

```
# only forward requests with an api version of 1.0x
gor --input-raw :8080 --output-http staging.com --http-allow-header api-version:^1\.0\d

# only forward requests NOT containing User-Agent header value "Replayed by Gor"
gor --input-raw :8080 --output-http staging.com --http-disallow-header "User-Agent: Replayed by Gor"
```

#### Filter based on HTTP method
Requests not matching a specified whitelist can be filtered out. For example to strip non-nullipotent requests:

```
gor --input-raw :80 --output-http "http://staging.server" \
    --http-allow-method GET \
    --http-allow-method OPTIONS
```


-----
You may also read about [[Request rewriting]], [[Rate limiting]] and [[Middleware]]

================================================
FILE: docs/Request-rewriting.md
================================================
Gor supports rewriting of URLs, URL params and headers, see below.

Rewriting may be useful if you test environment does not have the same data as your production, and you want to perform all actions in the context of `test` user: for example rewrite all API tokens to some test value. Other possible use cases are toggling features on/off using custom headers or rewriting URL's if they changed in the new environment.

For more complex logic you can use [Middleware](middleware.md).

#### Rewrite URL based on a mapping
`--http-rewrite-url` expects value in "<search>:<replace>" format: ":" is a dilimiter. In `<replace>` section you may use captured regexp group values. This works similar to `replace` method in Javascript or `gsub` in Ruby. 

```
# Rewrites all `/v1/user/<user_id>/ping` requests to `/v2/user/<user_id>/ping`
gor --input-raw :8080 --output-http staging.com --http-rewrite-url /v1/user/([^\\/]+)/ping:/v2/user/$1/ping
```

#### Set URL param
Set request url param, if param already exists it will be overwritten.
```
gor --input-raw :8080 --output-http staging.com --http-set-param api_key=1
```

#### Set Header
Set request header, if header already exists it will be overwritten. May be useful if you need to identify requests generated by Gor or enable feature flagged functionality in an application:

```
gor --input-raw :80 --output-http "http://staging.server" \
    --http-set-header "User-Agent: Replayed by Gor" \
    --http-set-header "Enable-Feature-X: true"
```

#### Host header
Host header gets special treatment. By default Host get set to the value specified in --output-http. If you manually set --http-set-header "Host: anonther.com", Gor will not override Host value.

If you app accepts traffic from multiple domains, and you want to keep original headers, there is specific `--http-original-host` with tells Gor do not touch Host header at all.


***

You may also read about [[Request filtering]], [[Rate limiting]] and [[Middleware]]


================================================
FILE: docs/Running-as-non-root-user.md
================================================
You can enable Gor for non-root users in a secure method by using the following commands

``` 
# Following commands assume that you put `gor` binary to /usr/local/bin
add gor
addgroup <username> gor
chgrp gor /usr/local/bin/gor
chmod 0750 /usr/local/bin/gor
setcap "cap_net_raw,cap_net_admin+eip" /usr/local/bin/gor
```
 
As a brief explanation of the above.
* We create a group called gor. 
* We then add the user you want to the new group so they will be able to use gor without sudo
* We then change the user/group of gor binary the new group.
* We then make sure the permissions are set on gor binary so that members of the group can execute it but other normal users cannot.
* We then use `setcap` to give the CAP_NET_RAW and CAP_NET_ADMIN privilege to the executable when it runs. This is so that Gor can open its raw socket which is not normally permitted unless you are root.

================================================
FILE: docs/Saving-and-Replaying-from-file.md
================================================
You can save requests to file, and replay them later. While replaying it will preserve the original time differences between requests. If you apply [percentage based limiting](Rate Limiting) timing between requests will be reduced or increased appropriately: this approach opens possibilities like load testing, see below.

```bash
# write to file
gor --input-raw :80 --output-file requests.log

# read from file
gor --input-file requests.gor --output-http "http://staging.com"
```

By default Gor writes files in chunks. This configurable using `--output-file-append` option: the flushed chunk is appended to existence file or not. The default is **false**. By default, `--output-file` flushes each chunk to a different path.

```bash
gor ... --output-file %Y%m%d.log
# append false
20140608_0.log
20140608_1.log
20140609_0.log
20140609_1.log
```

This makes parallel file processing easy. But if you want to disable this behavior, you can disable it by adding `--output-file-append` option:

```bash
gor ... --output-file %Y%m%d.log --output-file-append
# append true
20140608.log
20140609.log
```

If you run gor multiple times, and it finds existing files, it will continue from last known index.

### Chunk size

You can set chunk limits using `--output-file-size-limit` and `--output-file-queue-limit` options.
The length of the chunk queue and the size of each chunk, respectively. The default values are 256 and 32mb, respectively. The suffixes “k” (KB), “m” (MB), and “g” (GB) can be used for `output-file-size-limit`.
If you want to have only size constraint, you can set `--output-file-queue-limit` to 0, and vice versa.

```bash
gor --input-raw :80 --output-file %Y-%m-%d.gz --output-file-size-limit 256m --output-file-queue-limit 0
```

### Using date variables in file names
For example, you can tell to create new file each hour: `--output-file /mnt/logs/requests-%Y-%m-%d-%H.log`
It will create new file for each hour: requests-2016-06-01-12.log, requests-2016-06-01-13.log, ...

The time format used as part of the file name. The following characters are replaced with actual values when the file is created:

* `%Y`: year including the century (at least 4 digits)
* `%m`: month of the year (01..12)
* `%d`: Day of the month (01..31)
* `%H`: Hour of the day, 24-hour clock (00..23)
* `%M`: Minute of the hour (00..59)
* `%S`: Second of the minute (00..60)

The default format is `%Y%m%d%H`, which creates one file per hour.


### GZIP compression
To read or write GZIP compressed files ensure that file extension ends with ".gz": `--output-file log.gz`

### Replaying from multiple files

`--input-file` accepts file pattern, for example: `--input-file logs-2016-05-*`: it will replay all the files, sorting them in lexicographical order.

### Buffered file output
Gor has memory buffer when it writes to file, and continuously flush changes to the file. Flushing to file happens if the buffer is filled, forced flush every 1 second, or if Gor is closed. You can change it using `--output-file-flush-interval` option. It most cases it should not be touched.

### File format
HTTP requests stored as it is, plain text: headers and bodies. Requests separated by `\n🐵🙈🙉\n` line (using such sequence for uniqueness and fun). Before each request goes single line with meta information containing payload type (1 - request, 2 - response, 3 - replayed response), unique request ID (request and response have the same) and timestamp when request was made. An example of 2 requests:

```
1 d7123dasd913jfd21312dasdhas31 127345969\n
GET / HTTP/1.1\r\n
\r\n
\n
🐵🙈🙉
\n
POST /upload HTTP/1.1\r\n
Content-Length: 7\r\n
Host: www.w3.org\r\n
\r\n
a=1&b=2
```
Note that technically \r and \n symbols are invisible, and indicate new lines. I made them visible in example just to show how it looks on byte level.

Making it text friendly allows writing simple parsers and use console tools like `grep` to do an analysis. You can even edit them manually, but be sure that your file editor does not change line endings.

## Performance testing

Currently, this functionality supported only by `input-file` and only when using percentage based limiter. Unlike default limiter for `input-file` instead of dropping requests it will slowdown or speedup request emitting. Note that **limiter is applied to input**:

```
# Replay from file on 2x speed 
gor --input-file "requests.gor|200%" --output-http "staging.com"
```

Use `--stats --output-http-stats` to see latency stats.

### Looping files for replaying indefinitely
You can loop the same set of files, so when the last one replays all the requests, it will not stop, and will start from first one again. Having the only small amount of requests you can do extensive performance testing.
Pass `--input-file-loop` to make it work. 

***
You may also read about [[Capturing and replaying traffic]] and [[Rate limiting]]

================================================
FILE: docs/Troubleshooting.md
================================================
Gor can report stats on the `output-tcp` and `output-http` request queues. Stats are reported to the console every 5 seconds in the form `latest,mean,max,count,count/second` by using the `--output-http-stats` and `--output-tcp-stats` options.

Examples:

```
2014/04/23 21:17:50 output_tcp:latest,mean,max,count,count/second
2014/04/23 21:17:50 output_tcp:0,0,0,0,0
2014/04/23 21:17:55 output_tcp:1,1,2,68,13
2014/04/23 21:18:00 output_tcp:1,1,2,92,18
2014/04/23 21:18:05 output_tcp:1,1,2,119,23
```

```
2014/04/23 21:19:46 output_http:latest,mean,max,count,count/second
2014/04/23 21:19:46 output_http:0,0,0,0,0
2014/04/23 21:19:51 output_http:0,0,0,0,0
2014/04/23 21:19:56 output_http:0,0,0,0,0
2014/04/23 21:20:01 output_http:1,0,1,50,10
2014/04/23 21:20:06 output_http:1,1,4,72,14
2014/04/23 21:20:11 output_http:1,0,1,179,35
2014/04/23 21:20:16 output_http:1,0,1,148,29
2014/04/23 21:20:21 output_http:1,1,2,91,18
2014/04/23 21:20:26 output_http:1,1,2,150,30
2014/04/23 21:18:15 output_http:100,99,100,70,14
2014/04/23 21:18:21 output_http:100,99,100,55,11
```

### How can I tell if I have bottlenecks?
Key areas that sometimes experience bottlenecks are the output-tcp and output-http functions which have internal queues for requests. Each queue has an upper limit of 100. Enable stats reporting to see if any queues are experiencing bottleneck behavior.
 
#### Output HTTP bottlenecks
When running a Gor replay the output-http feature may bottleneck if:

  * the replay has inadequate bandwidth. If the replay is receiving or sending more messages than its network adapter can handle the output-http-stats  may report that the output-http queue is filling up. See if there is a way to upgrade the replay's bandwidth.
  * with `--output-http-workers` set to anything other than `-1` the `-output-http` target is unable to respond to messages in a timely manner. The http output workers which take messages off the output-http queue, process the request, and ensure that the request did not result in an error may not be able to keep up with the number of incoming requests. If the replay is not using dynamic worker scaling (`--output-http-workers=-1`)  The optimal number of output-http-workers can be determined with the formula `output-workers = (Average number of requests per second)/(Average target response time per second)`.

#### Output TCP bottlenecks
When using the Gor listener the output-tcp feature may bottleneck if:

  * the replay is unable to accept and process more requests than the listener is able generate. Prior to troubleshooting the output-tcp bottleneck, ensure that the replay target is not experiencing any bottlenecks. 
  * the replay target has inadequate bandwidth to handle all its incoming requests.  If a replay target's incoming bandwidth is maxed out the output-tcp-stats may report that the output-tcp queue is filling up. See if there is a way to upgrade the replay's bandwidth.


#### Tuning

To achieve the top most performance you should tune the source server system limits:

    net.ipv4.tcp_max_tw_buckets = 65536
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_tw_reuse = 0
    net.ipv4.tcp_max_syn_backlog = 131072
    net.ipv4.tcp_syn_retries = 3
    net.ipv4.tcp_synack_retries = 3
    net.ipv4.tcp_retries1 = 3
    net.ipv4.tcp_retries2 = 8
    net.ipv4.tcp_rmem = 16384 174760 349520
    net.ipv4.tcp_wmem = 16384 131072 262144
    net.ipv4.tcp_mem = 262144 524288 1048576
    net.ipv4.tcp_max_orphans = 65536
    net.ipv4.tcp_fin_timeout = 10
    net.ipv4.tcp_low_latency = 1
    net.ipv4.tcp_syncookies = 0
***

### Gor is crashing with following stacktrace
```
fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0x63 pc=0x7ffcdfdf8b2c]

runtime stack:
runtime.throw(0xad8380, 0x2a)
	/usr/local/go/src/runtime/panic.go:547 +0x90
runtime.sigpanic()
	/usr/local/go/src/runtime/sigpanic_unix.go:12 +0x5a

goroutine 103 [syscall, locked to thread]:
runtime.cgocall(0x7b35a0, 0xc82121f1e8, 0x0)
	/usr/local/go/src/runtime/cgocall.go:123 +0x11b fp=0xc82121f188 sp=0xc82121f158
net._C2func_getaddrinfo(0x7ffcec0008c0, 0x0, 0xc821b221e0, 0xc8217b2b18, 0x0, 0x0, 0x0)
	??:0 +0x55 fp=0xc82121f1e8 sp=0xc82121f188
net.cgoLookupIPCNAME(0x7fffb17208ab, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb17200)
```

There is a chance that you hit Go bug. The crash comes from the CGO version of DNS resolver.
By default Go based version used, but ins some cases [it switches to CGO based](https://golang.org/pkg/net/#hdr-Name_Resolution). It is possible to force Go based DNS resolver using GODEBUG environment variable:
`sudo GODEBUG="netdns=go" ./gor --input-raw :80 --output-http staging.env`



Also, see [[FAQ]]

================================================
FILE: docs/_Footer.md
================================================
[Website](https://goreplay.org) | [PRO version](https://goreplay.org/pro.html) | [[Getting started]] | [[FAQ]] | [Join newsletter](https://www.getdrip.com/forms/89690474/submissions/new)

================================================
FILE: docs/_config.yml
================================================
theme: jekyll-theme-cayman

================================================
FILE: docs/commercial/collaboration.md
================================================
Collaboration is difficult with commercial closed source but I do want to keep as much of the OSS ethos as possible available to customers who want to fix it themselves.

## Legal

In order to unambiguously own and sell Gor commercial products, I must have the copyright associated with the entire codebase.  Any code you create which is merged must be owned by me.  That's not me trying to be a jerk, that's just the way it works.

## Application

If you wish access to the product repository so you can send a PR, just open a new Gor issue and include the following info:

1. the email address that bought the license, a max of one collaborator per license
1. the following statement "I assign all rights, including copyright, to any future Gor work by myself to Leonid Bugaev"

You should be granted access to the private repo soon after.

## Notes

1. You should **never** work on the master branch.  Only I may merge changes.
1. I may revoke access for any reason at any time.  Access is not guaranteed with purchase.

================================================
FILE: docs/commercial/faq.md
================================================
### What are GoReplay PRO and GoReplay Enterprise?

[GoReplay PRO](https://goreplay.org/pro.html) and GoReplay Enterprise are extensions to GoReplay which add more functionality and provide additional support options for customers.

### Is there a trial version?

There's no free trial but we do offer a 14 day period with full refund if it does not work for you.

### What is the license?

See [COMM-LICENSE](https://github.com/buger/gor/blob/master/COMM-LICENSE) in the root of the GoReplay repo.

### How does PRO licensing work?

Every organization running GoReplay Pro on its own servers must have a license.  There's no limit to the amount of servers or environments used by that organization.

### How does Enterprise licensing work?

Every organization running Gor Enterprise on its own servers must have a license. There's **no limit** to the amount of servers or environments used by that organization.

### What happens if my subscription lapses?

You must have an active subscription to run GoReplay Pro or Enterprise.  After a one week grace period, you'll lose access to binaries and priority support.  You won't get any more updates or bug fixes.

### How do I buy GoReplay Enterprise?

Send email to [support&#64;gortool.com](mailto:support&#64;gortool.com) with your info.  A PDF quote will be emailed to you with the price.  Reply to that email with your purchase order or just "Sounds good" and we will send an invoice which can be paid with a credit card, ACH bank transfer or a paper check.

### Can I upgrade from GoReplay Pro?

Yes!  Current subscribers can upgrade by [requesting a quote](mailto:support&#64;gortool.com).  **Please note that you are an existing Pro subscriber.**  We will add a one-time discount on your first invoice to reflect any remaining Pro subscription credit.  If you purchased GoReplay Pro 6 months ago for $950, you'll get a $475 discount.

### Can I distribute GoReplay PRO or Enterprise to my customers?

This is a common requirement for "on-site installs" or "appliances" sold to large corporations.

The standard license is appropriate for SaaS usage as it does not allow distribution.  GoReplay PRO and Enterprise have an Appliance license option which **does** allow you to distribute them.  The Appliance license is $9,500/yr for Pro and $19,500/yr for Enterprise.  It allows you to distribute the Pro or Enterprise binaries as part of your application and each of your customers to run GoReplay Pro or Enterprise. Email [support&#64;gortool.com](mailto:support&#64;gortool.com) to purchase.

### Can you transfer a license?

Licenses are **not** transferable to another company.  We will transfer the license from a user-specific email to a group email address (e.g. john_smith@example.com -> tech@example.com) but only for **the same domain**.  It is strongly recommended that you buy the license using a group email address so the license is not attached to any one employee's email address.

### What does the license require me to do?

Your purchase gets you a unique access URL for downloading the Pro and/or Enterprise binaries.  The license agreement requires you to keep this access URL private.  If we find your access URL is ever publicized:

1. We'll send you a warning email with details.  You need to remove the content and send a new email address so we can generate a new access URL for you.  The old access URL will stop working immediately so you'll need to update your apps.
2. If your access URL is publicized a second time, we reserve the right to permanently remove access.

### Can I get a refund?

Yes, up to two weeks after purchase.  Let us know the reason and maybe we can help but either way it's not a problem.  Email [support&#64;gortool.com](mailto:support&#64;gortool.com).

### How do I update my credit card info?

If you purchased GoReplay Enterprise, there's nothing to do.  Each annual invoice is paid separately.

If you purchased GoReplay PRO, log into [Gumroad](https://gumroad.com) with your email address, click the Billing tab and enter your new card.  I can't provide support for the Gumroad website and don't have the ability to edit customer info - if you can't log in or change your credit card, you can always let your current subscription expire and purchase a new subscription.

================================================
FILE: docs/commercial/support.md
================================================
Gor offers only community support.  Gor Pro and Enterprise offer priority support via email.

## Priority Support

Covers 1 incident per quarter, with a max response time of 2 working days. Scope is limited to Gor and Gor Pro and Enterprise features and APIs, not the application or infrastructure.  For support, email **support** AT **gortool.com**.  Please email using the same domain as the original license email or explain your connection to the licensed company.

More aggressive support contracts (phone, quicker response time) are available separately, email with your needs.

## Onboarding

Enterprise customers may request a one hour video chat session with @buger to discuss their application(s), requirements and how best to leverage the various Gor features.  Contact support to set up your session.

================================================
FILE: docs/css/breadcrumbs.css
================================================
.wy-breadcrumbs li {
  display: inline-block;
}

.wy-breadcrumbs li.wy-breadcrumbs-aside {
  float: right;
}

.wy-breadcrumbs li a {
  display: inline-block;
  padding: 5px;
}

.wy-breadcrumbs li a:first-child {
  padding-left: 0;
}

.wy-breadcrumbs-extra {
  margin-bottom: 0;
  color: #b3b3b3;
  font-size: 80%;
  display: inline-block;
}

@media screen and (max-width: 480px) {
  .wy-breadcrumbs-extra {
    display: none;
  }

  .wy-breadcrumbs li.wy-breadcrumbs-aside {
    display: none;
  }
}

@media print {
  .wy-breadcrumbs li.wy-breadcrumbs-aside {
    display: none;
  }
}

================================================
FILE: docs/css/code.css
================================================
.codeblock-example {
  border: 1px solid #e1e4e5;
  border-bottom: none;
  padding: 24px;
  padding-top: 48px;
  font-weight: 500;
  background: #fff;
  position: relative;
}

.codeblock-example:after {
  content: "Example";
  position: absolute;
  top: 0;
  left: 0;
  background: #9B59B6;
  color: #fff;
  padding: 6px 12px;
}

.codeblock-example.prettyprint-example-only {
  border: 1px solid #e1e4e5;
  margin-bottom: 24px;
}

.codeblock,
pre.literal-block,
.rst-content .literal-block,
.rst-content pre.literal-block,
div[class^='highlight'] {
  border: 1px solid #e1e4e5;
  padding: 0;
  overflow-x: auto;
  background: #fff;
  margin: 1px 0 24px;
}

.codeblock div[class^='highlight'],
pre.literal-block div[class^='highlight'],
.rst-content .literal-block div[class^='highlight'],
div[class^='highlight'] div[class^='highlight'] {
  border: none;
  background: none;
  margin: 0;
}

div[class^='highlight'] td.code {
  width: 100%;
}

.linenodiv pre {
  border-right: solid 1px #e6e9ea;
  margin: 0;
  padding: 12px;
  font-family: "Source Code Pro","Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;
  font-size: 12px;
  line-height: 1.5;
  color: #d9d9d9;
}

div[class^='highlight'] pre {
  white-space: pre;
  margin: 0;
  padding: 12px;
  font-family: "Source Code Pro","Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;
  font-size: 12px;
  line-height: 1.5;
  display: block;
  overflow: auto;
  color: #404040;
}

@media print {
  .codeblock,
  pre.literal-block,
  .rst-content .literal-block,
  .rst-content pre.literal-block,
  div[class^='highlight'],
  div[class^='highlight'] pre {
    white-space: pre-wrap;
  }

}

.hll {
  background-color: #ffc;
  margin: 0 -12px;
  padding: 0 12px;
  display: block;
}

.c {
  color: #998;
  font-style: italic;
}

.err {
  color: #a61717;
  background-color: #e3d2d2;
}

.k {
  font-weight: 700;
}

.o {
  font-weight: 700;
}

.cm {
  color: #998;
  font-style: italic;
}

.cp {
  color: #999;
  font-weight: 700;
}

.c1 {
  color: #998;
  font-style: italic;
}

.cs {
  color: #999;
  font-weight: 700;
  font-style: italic;
}

.gd {
  color: #000;
  background-color: #fdd;
}

.gd .x {
  color: #000;
  background-color: #faa;
}

.ge {
  font-style: italic;
}

.gr {
  color: #a00
}

.gh {
  color: #999;
}

.gi {
  color: #000;
  background-color: #dfd;
}

.gi .x {
  color: #000;
  background-color: #afa;
}

.go {
  color: #888;
}

.gp {
  color: #555;
}

.gs {
  font-weight: 700;
}

.gu {
  color: purple;
  font-weight: 700;
}

.gt {
  color: #a00;
}

.kc {
  font-weight: 700;
}

.kd {
  font-weight: 700;
}

.kn {
  font-weight: 700;
}

.kp {
  font-weight: 700;
}

.kr {
  font-weight: 700;
}

.kt {
  color: #458;
  font-weight: 700;
}

.m {
  color: #099;
}

.s {
  color: #d14;
}

.n {
  color: #333;
}

.na {
  color: teal;
}

.nb {
  color: #0086b3;
}

.nc {
  color: #458;
  font-weight: 700;
}

.no {
  color: teal;
}

.ni {
  color: purple;
}

.ne {
  color: #900;
  font-weight: 700;
}

.nf {
  color: #900;
  font-weight: 700;
}

.nn {
  color: #555;
}

.nt {
  color: navy;
}

.nv {
  color: teal;
}

.ow {
  font-weight: 700;
}

.w {
  color: #bbb;
}

.mf {
  color: #099;
}

.mh {
  color: #099;
}

.mi {
  color: #099;
}

.mo {
  color: #099;
}

.sb {
  color: #d14;
}

.sc {
  color: #d14;
}

.sd {
  color: #d14;
}

.s2 {
  color: #d14
}

.se {
  color: #d14;
}

.sh {
  color: #d14;
}

.si {
  color: #d14;
}

.sx {
  color: #d14;
}

.sr {
  color: #009926;
}

.s1 {
  color: #d14;
}

.ss {
  color: #990073;
}

.bp {
  color: #999;
}

.vc {
  color: teal;
}

.vg {
  color: teal;
}

.vi {
  color: teal;
}

.il {
  color: #099;
}

.gc {
  color: #999;
  background-color: #EAF2F5;
}

================================================
FILE: docs/css/fabric.css
================================================
/* Taken from https://docs.fabric.io/apple/fabric/overview.html */

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box
}

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section {
  display: block
}

audio,
canvas,
video {
  display: inline-block;
  *display: inline;
  *zoom: 1
}

audio:not([controls]) {
  display: none
}

[hidden] {
  display: none
}

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box
}

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%
}

body {
  margin: 0
}

a:hover,
a:active {
  outline: 0
}

abbr[title] {
  border-bottom: 1px dotted
}

b,
strong {
  font-weight: 700
}

blockquote {
  margin: 0
}

dfn {
  font-style: italic
}

ins {
  background: #ff9;
  color: #000;
  text-decoration: none
}

mark {
  background: #ff0;
  color: #000;
  font-style: italic;
  font-weight: 700
}

pre,
code,
.rst-content tt,
.rst-content code,
kbd,
samp {
  font-family: monospace,serif;
  _font-family: "courier new",monospace;
  font-size: 1em
}

pre {
  white-space: pre
}

q {
  quotes: none
}

q:before,
q:after {
  content: "";
  content: none
}

small {
  font-size: 85%
}

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline
}

sup {
  top: -.5em
}

sub {
  bottom: -.25em
}

ul,
ol,
dl {
  margin: 0;
  padding: 0;
  list-style: none;
  list-style-image: none
}

li {
  list-style: none
}

dd {
  margin: 0
}

img {
  border: 0;
  -ms-interpolation-mode: bicubic;
  vertical-align: middle;
  max-width: 100%
}

svg:not(:root) {
  overflow: hidden
}

figure {
  margin: 0
}

form {
  margin: 0
}

fieldset {
  border: 0;
  margin: 0;
  padding: 0
}

label {
  cursor: pointer
}

legend {
  border: 0;
  *margin-left: -7px;
  padding: 0;
  white-space: normal
}

button,
input,
select,
textarea {
  font-size: 100%;
  margin: 0;
  vertical-align: baseline;
  *vertical-align: middle
}

button,
input {
  line-height: normal
}

button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
  cursor: pointer;
  -webkit-appearance: button;
  *overflow: visible
}

button[disabled],
input[disabled] {
  cursor: default
}

input[type="checkbox"],
input[type="radio"] {
  box-sizing: border-box;
  padding: 0;
  *width: 13px;
  *height: 13px
}

input[type="search"] {
  -webkit-appearance: textfield;
  -moz-box-sizing: content-box;
  -webkit-box-sizing: content-box;
  box-sizing: content-box
}

input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none
}

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0
}

textarea {
  overflow: auto;
  vertical-align: top;
  resize: vertical
}

table {
  border-collapse: collapse;
  border-spacing: 0
}

td {
  vertical-align: top
}

.chromeframe {
  margin: .2em 0;
  background: #ccc;
  color: #000;
  padding: .2em 0
}

.ir {
  display: block;
  border: 0;
  text-indent: -999em;
  overflow: hidden;
  background-color: transparent;
  background-repeat: no-repeat;
  text-align: left;
  direction: ltr;
  *line-height: 0
}

.ir br {
  display: none
}

.hidden {
  display: none!important;
  visibility: hidden
}

.visuallyhidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px
}

.visuallyhidden.focusable:active,
.visuallyhidden.focusable:focus {
  clip: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  position: static;
  width: auto
}

.invisible {
  visibility: hidden
}

.relative {
  position: relative
}

big,
small {
  font-size: 100%
}

@media print {
  html,
  body,
  section {
    background: none!important
  }

  * {
    box-shadow: none!important;
    text-shadow: none!important;
    filter: none!important;
    -ms-filter: none!important
  }

  a,
  .ir a:after,
  a[href^="javascript:"]:after,
  a[href^="#"]:after {
    content: ""
  }

  pre,
  blockquote {
    page-break-inside: avoid
  }

  thead {
    display: table-header-group
  }

  tr,
  img {
    page-break-inside: avoid
  }

  img {
    max-width: 100%!important
  }

  @page {
    margin: .5cm
  }

  p,
  h2,
  h3 {
    orphans: 3;
    widows: 3
  }

  h2,
  h3 {
    page-break-after: avoid
  }

}

.fa:before,
.wy-menu-vertical li span.toctree-expand:before,
.wy-menu-vertical li.on a span.toctree-expand:before,
.wy-menu-vertical li.current>a span.toctree-expand:before,
.rst-content .admonition-title:before,
.rst-content h1 .headerlink:before,
.rst-content h2 .headerlink:before,
.rst-content h3 .headerlink:before,
.rst-content h4 .headerlink:before,
.rst-content h5 .headerlink:before,
.rst-content h6 .headerlink:before,
.rst-content dl dt .headerlink:before,
.rst-content p.caption .headerlink:before,
.rst-content tt.download span:first-child:before,
.rst-content code.download span:first-child:before,
.icon:before,
.wy-dropdown .caret:before,
.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,
.wy-alert,
.rst-content .note,
.rst-content .attention,
.rst-content .caution,
.rst-content .danger,
.rst-content .error,
.rst-content .hint,
.rst-content .important,
.rst-content .tip,
.rst-content .warning,
.rst-content .seealso,
.rst-content .admonition-todo,
.btn,
input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="datetime"],
input[type="datetime-local"],
input[type="week"],
input[type="number"],
input[type="search"],
input[type="tel"],
input[type="color"],
select,
textarea,
.wy-menu-vertical li.on a,
.wy-menu-vertical li.current>a,
.wy-side-nav-search>a,
.wy-side-nav-search .wy-dropdown>a,
.wy-nav-top a {
  -webkit-font-smoothing: antialiased
}

.clearfix {
  *zoom: 1
}

.clearfix:before,
.clearfix:after {
  display: table;
  content: ""
}

.clearfix:after {
  clear: both
}

@font-face {
  font-family: 'FontAwesome';
  src: url(../fonts/fontawesome-webfont.eot?v=4.2.0);
  src: url(../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0) format("embedded-opentype"),url(../fonts/fontawesome-webfont.woff?v=4.2.0) format("woff"),url(../fonts/fontawesome-webfont.ttf?v=4.2.0) format("truetype"),url(../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular) format("svg");
  font-weight: 400;
  font-style: normal
}

.fa,
.wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.current>a span.toctree-expand,
.rst-content .admonition-title,
.rst-content h1 .headerlink,
.rst-content h2 .headerlink,
.rst-content h3 .headerlink,
.rst-content h4 .headerlink,
.rst-content h5 .headerlink,
.rst-content h6 .headerlink,
.rst-content dl dt .headerlink,
.rst-content p.caption .headerlink,
.rst-content tt.download span:first-child,
.rst-content code.download span:first-child,
.icon {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale
}

.fa-lg {
  font-size: 1.33333em;
  line-height: .75em;
  vertical-align: -15%
}

.fa-2x {
  font-size: 2em
}

.fa-3x {
  font-size: 3em
}

.fa-4x {
  font-size: 4em
}

.fa-5x {
  font-size: 5em
}

.fa-fw {
  width: 1.28571em;
  text-align: center
}

.fa-ul {
  padding-left: 0;
  margin-left: 2.14286em;
  list-style-type: none
}

.fa-ul>li {
  position: relative
}

.fa-li {
  position: absolute;
  left: -2.14286em;
  width: 2.14286em;
  top: .14286em;
  text-align: center
}

.fa-li.fa-lg {
  left: -1.85714em
}

.fa-border {
  padding: .2em .25em .15em;
  border: solid .08em #eee;
  border-radius: .1em
}

.pull-right {
  float: right
}

.pull-left {
  float: left
}

.fa.pull-left,
.wy-menu-vertical li span.pull-left.toctree-expand,
.wy-menu-vertical li.on a span.pull-left.toctree-expand,
.wy-menu-vertical li.current>a span.pull-left.toctree-expand,
.rst-content .pull-left.admonition-title,
.rst-content h1 .pull-left.headerlink,
.rst-content h2 .pull-left.headerlink,
.rst-content h3 .pull-left.headerlink,
.rst-content h4 .pull-left.headerlink,
.rst-content h5 .pull-left.headerlink,
.rst-content h6 .pull-left.headerlink,
.rst-content dl dt .pull-left.headerlink,
.rst-content p.caption .pull-left.headerlink,
.rst-content tt.download span.pull-left:first-child,
.rst-content code.download span.pull-left:first-child,
.pull-left.icon {
  margin-right: .3em
}

.fa.pull-right,
.wy-menu-vertical li span.pull-right.toctree-expand,
.wy-menu-vertical li.on a span.pull-right.toctree-expand,
.wy-menu-vertical li.current>a span.pull-right.toctree-expand,
.rst-content .pull-right.admonition-title,
.rst-content h1 .pull-right.headerlink,
.rst-content h2 .pull-right.headerlink,
.rst-content h3 .pull-right.headerlink,
.rst-content h4 .pull-right.headerlink,
.rst-content h5 .pull-right.headerlink,
.rst-content h6 .pull-right.headerlink,
.rst-content dl dt .pull-right.headerlink,
.rst-content p.caption .pull-right.headerlink,
.rst-content tt.download span.pull-right:first-child,
.rst-content code.download span.pull-right:first-child,
.pull-right.icon {
  margin-left: .3em
}

.fa,
.wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.current>a span.toctree-expand,
.rst-content .admonition-title,
.rst-content h1 .headerlink,
.rst-content h2 .headerlink,
.rst-content h3 .headerlink,
.rst-content h4 .headerlink,
.rst-content h5 .headerlink,
.rst-content h6 .headerlink,
.rst-content dl dt .headerlink,
.rst-content p.caption .headerlink,
.rst-content tt.download span:first-child,
.rst-content code.download span:first-child,
.icon,
.wy-dropdown .caret,
.wy-inline-validate.wy-inline-validate-success .wy-input-context,
.wy-inline-validate.wy-inline-validate-danger .wy-input-context,
.wy-inline-validate.wy-inline-validate-warning .wy-input-context,
.wy-inline-validate.wy-inline-validate-info .wy-input-context {
  font-family: inherit
}

.fa:before,
.wy-menu-vertical li span.toctree-expand:before,
.wy-menu-vertical li.on a span.toctree-expand:before,
.wy-menu-vertical li.current>a span.toctree-expand:before,
.rst-content .admonition-title:before,
.rst-content h1 .headerlink:before,
.rst-content h2 .headerlink:before,
.rst-content h3 .headerlink:before,
.rst-content h4 .headerlink:before,
.rst-content h5 .headerlink:before,
.rst-content h6 .headerlink:before,
.rst-content dl dt .headerlink:before,
.rst-content p.caption .headerlink:before,
.rst-content tt.download span:first-child:before,
.rst-content code.download span:first-child:before,
.icon:before,
.wy-dropdown .caret:before,
.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,
.wy-inline-validate.wy-inline-validate-info .wy-input-context:before {
  font-family: "FontAwesome";
  display: inline-block;
  font-style: normal;
  font-weight: 400;
  line-height: 1;
  text-decoration: inherit
}

a .fa,
a .wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li a span.toctree-expand,
.wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.current>a span.toctree-expand,
a .rst-content .admonition-title,
.rst-content a .admonition-title,
a .rst-content h1 .headerlink,
.rst-content h1 a .headerlink,
a .rst-content h2 .headerlink,
.rst-content h2 a .headerlink,
a .rst-content h3 .headerlink,
.rst-content h3 a .headerlink,
a .rst-content h4 .headerlink,
.rst-content h4 a .headerlink,
a .rst-content h5 .headerlink,
.rst-content h5 a .headerlink,
a .rst-content h6 .headerlink,
.rst-content h6 a .headerlink,
a .rst-content dl dt .headerlink,
.rst-content dl dt a .headerlink,
a .rst-content p.caption .headerlink,
.rst-content p.caption a .headerlink,
a .rst-content tt.download span:first-child,
.rst-content tt.download a span:first-child,
a .rst-content code.download span:first-child,
.rst-content code.download a span:first-child,
a .icon {
  display: inline-block;
  text-decoration: inherit
}

.btn .fa,
.btn .wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li .btn span.toctree-expand,
.btn .wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.on a .btn span.toctree-expand,
.btn .wy-menu-vertical li.current>a span.toctree-expand,
.wy-menu-vertical li.current>a .btn span.toctree-expand,
.btn .rst-content .admonition-title,
.rst-content .btn .admonition-title,
.btn .rst-content h1 .headerlink,
.rst-content h1 .btn .headerlink,
.btn .rst-content h2 .headerlink,
.rst-content h2 .btn .headerlink,
.btn .rst-content h3 .headerlink,
.rst-content h3 .btn .headerlink,
.btn .rst-content h4 .headerlink,
.rst-content h4 .btn .headerlink,
.btn .rst-content h5 .headerlink,
.rst-content h5 .btn .headerlink,
.btn .rst-content h6 .headerlink,
.rst-content h6 .btn .headerlink,
.btn .rst-content dl dt .headerlink,
.rst-content dl dt .btn .headerlink,
.btn .rst-content p.caption .headerlink,
.rst-content p.caption .btn .headerlink,
.btn .rst-content tt.download span:first-child,
.rst-content tt.download .btn span:first-child,
.btn .rst-content code.download span:first-child,
.rst-content code.download .btn span:first-child,
.btn .icon,
.nav .fa,
.nav .wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li .nav span.toctree-expand,
.nav .wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.on a .nav span.toctree-expand,
.nav .wy-menu-vertical li.current>a span.toctree-expand,
.wy-menu-vertical li.current>a .nav span.toctree-expand,
.nav .rst-content .admonition-title,
.rst-content .nav .admonition-title,
.nav .rst-content h1 .headerlink,
.rst-content h1 .nav .headerlink,
.nav .rst-content h2 .headerlink,
.rst-content h2 .nav .headerlink,
.nav .rst-content h3 .headerlink,
.rst-content h3 .nav .headerlink,
.nav .rst-content h4 .headerlink,
.rst-content h4 .nav .headerlink,
.nav .rst-content h5 .headerlink,
.rst-content h5 .nav .headerlink,
.nav .rst-content h6 .headerlink,
.rst-content h6 .nav .headerlink,
.nav .rst-content dl dt .headerlink,
.rst-content dl dt .nav .headerlink,
.nav .rst-content p.caption .headerlink,
.rst-content p.caption .nav .headerlink,
.nav .rst-content tt.download span:first-child,
.rst-content tt.download .nav span:first-child,
.nav .rst-content code.download span:first-child,
.rst-content code.download .nav span:first-child,
.nav .icon {
  display: inline
}

.btn .fa.fa-large,
.btn .wy-menu-vertical li span.fa-large.toctree-expand,
.wy-menu-vertical li .btn span.fa-large.toctree-expand,
.btn .rst-content .fa-large.admonition-title,
.rst-content .btn .fa-large.admonition-title,
.btn .rst-content h1 .fa-large.headerlink,
.rst-content h1 .btn .fa-large.headerlink,
.btn .rst-content h2 .fa-large.headerlink,
.rst-content h2 .btn .fa-large.headerlink,
.btn .rst-content h3 .fa-large.headerlink,
.rst-content h3 .btn .fa-large.headerlink,
.btn .rst-content h4 .fa-large.headerlink,
.rst-content h4 .btn .fa-large.headerlink,
.btn .rst-content h5 .fa-large.headerlink,
.rst-content h5 .btn .fa-large.headerlink,
.btn .rst-content h6 .fa-large.headerlink,
.rst-content h6 .btn .fa-large.headerlink,
.btn .rst-content dl dt .fa-large.headerlink,
.rst-content dl dt .btn .fa-large.headerlink,
.btn .rst-content p.caption .fa-large.headerlink,
.rst-content p.caption .btn .fa-large.headerlink,
.btn .rst-content tt.download span.fa-large:first-child,
.rst-content tt.download .btn span.fa-large:first-child,
.btn .rst-content code.download span.fa-large:first-child,
.rst-content code.download .btn span.fa-large:first-child,
.btn .fa-large.icon,
.nav .fa.fa-large,
.nav .wy-menu-vertical li span.fa-large.toctree-expand,
.wy-menu-vertical li .nav span.fa-large.toctree-expand,
.nav .rst-content .fa-large.admonition-title,
.rst-content .nav .fa-large.admonition-title,
.nav .rst-content h1 .fa-large.headerlink,
.rst-content h1 .nav .fa-large.headerlink,
.nav .rst-content h2 .fa-large.headerlink,
.rst-content h2 .nav .fa-large.headerlink,
.nav .rst-content h3 .fa-large.headerlink,
.rst-content h3 .nav .fa-large.headerlink,
.nav .rst-content h4 .fa-large.headerlink,
.rst-content h4 .nav .fa-large.headerlink,
.nav .rst-content h5 .fa-large.headerlink,
.rst-content h5 .nav .fa-large.headerlink,
.nav .rst-content h6 .fa-large.headerlink,
.rst-content h6 .nav .fa-large.headerlink,
.nav .rst-content dl dt .fa-large.headerlink,
.rst-content dl dt .nav .fa-large.headerlink,
.nav .rst-content p.caption .fa-large.headerlink,
.rst-content p.caption .nav .fa-large.headerlink,
.nav .rst-content tt.download span.fa-large:first-child,
.rst-content tt.download .nav span.fa-large:first-child,
.nav .rst-content code.download span.fa-large:first-child,
.rst-content code.download .nav span.fa-large:first-child,
.nav .fa-large.icon {
  line-height: .9em
}

.btn .fa.fa-spin,
.btn .wy-menu-vertical li span.fa-spin.toctree-expand,
.wy-menu-vertical li .btn span.fa-spin.toctree-expand,
.btn .rst-content .fa-spin.admonition-title,
.rst-content .btn .fa-spin.admonition-title,
.btn .rst-content h1 .fa-spin.headerlink,
.rst-content h1 .btn .fa-spin.headerlink,
.btn .rst-content h2 .fa-spin.headerlink,
.rst-content h2 .btn .fa-spin.headerlink,
.btn .rst-content h3 .fa-spin.headerlink,
.rst-content h3 .btn .fa-spin.headerlink,
.btn .rst-content h4 .fa-spin.headerlink,
.rst-content h4 .btn .fa-spin.headerlink,
.btn .rst-content h5 .fa-spin.headerlink,
.rst-content h5 .btn .fa-spin.headerlink,
.btn .rst-content h6 .fa-spin.headerlink,
.rst-content h6 .btn .fa-spin.headerlink,
.btn .rst-content dl dt .fa-spin.headerlink,
.rst-content dl dt .btn .fa-spin.headerlink,
.btn .rst-content p.caption .fa-spin.headerlink,
.rst-content p.caption .btn .fa-spin.headerlink,
.btn .rst-content tt.download span.fa-spin:first-child,
.rst-content tt.download .btn span.fa-spin:first-child,
.btn .rst-content code.download span.fa-spin:first-child,
.rst-content code.download .btn span.fa-spin:first-child,
.btn .fa-spin.icon,
.nav .fa.fa-spin,
.nav .wy-menu-vertical li span.fa-spin.toctree-expand,
.wy-menu-vertical li .nav span.fa-spin.toctree-expand,
.nav .rst-content .fa-spin.admonition-title,
.rst-content .nav .fa-spin.admonition-title,
.nav .rst-content h1 .fa-spin.headerlink,
.rst-content h1 .nav .fa-spin.headerlink,
.nav .rst-content h2 .fa-spin.headerlink,
.rst-content h2 .nav .fa-spin.headerlink,
.nav .rst-content h3 .fa-spin.headerlink,
.rst-content h3 .nav .fa-spin.headerlink,
.nav .rst-content h4 .fa-spin.headerlink,
.rst-content h4 .nav .fa-spin.headerlink,
.nav .rst-content h5 .fa-spin.headerlink,
.rst-content h5 .nav .fa-spin.headerlink,
.nav .rst-content h6 .fa-spin.headerlink,
.rst-content h6 .nav .fa-spin.headerlink,
.nav .rst-content dl dt .fa-spin.headerlink,
.rst-content dl dt .nav .fa-spin.headerlink,
.nav .rst-content p.caption .fa-spin.headerlink,
.rst-content p.caption .nav .fa-spin.headerlink,
.nav .rst-content tt.download span.fa-spin:first-child,
.rst-content tt.download .nav span.fa-spin:first-child,
.nav .rst-content code.download span.fa-spin:first-child,
.rst-content code.download .nav span.fa-spin:first-child,
.nav .fa-spin.icon {
  display: inline-block
}

.btn.fa:before,
.wy-menu-vertical li span.btn.toctree-expand:before,
.rst-content .btn.admonition-title:before,
.rst-content h1 .btn.headerlink:before,
.rst-content h2 .btn.headerlink:before,
.rst-content h3 .btn.headerlink:before,
.rst-content h4 .btn.headerlink:before,
.rst-content h5 .btn.headerlink:before,
.rst-content h6 .btn.headerlink:before,
.rst-content dl dt .btn.headerlink:before,
.rst-content p.caption .btn.headerlink:before,
.rst-content tt.download span.btn:first-child:before,
.rst-content code.download span.btn:first-child:before,
.btn.icon:before {
  opacity: .5;
  -webkit-transition: opacity .05s ease-in;
  -moz-transition: opacity .05s ease-in;
  transition: opacity .05s ease-in
}

.btn.fa:hover:before,
.wy-menu-vertical li span.btn.toctree-expand:hover:before,
.rst-content .btn.admonition-title:hover:before,
.rst-content h1 .btn.headerlink:hover:before,
.rst-content h2 .btn.headerlink:hover:before,
.rst-content h3 .btn.headerlink:hover:before,
.rst-content h4 .btn.headerlink:hover:before,
.rst-content h5 .btn.headerlink:hover:before,
.rst-content h6 .btn.headerlink:hover:before,
.rst-content dl dt .btn.headerlink:hover:before,
.rst-content p.caption .btn.headerlink:hover:before,
.rst-content tt.download span.btn:first-child:hover:before,
.rst-content code.download span.btn:first-child:hover:before,
.btn.icon:hover:before {
  opacity: 1
}

.btn-mini .fa:before,
.btn-mini .wy-menu-vertical li span.toctree-expand:before,
.wy-menu-vertical li .btn-mini span.toctree-expand:before,
.btn-mini .rst-content .admonition-title:before,
.rst-content .btn-mini .admonition-title:before,
.btn-mini .rst-content h1 .headerlink:before,
.rst-content h1 .btn-mini .headerlink:before,
.btn-mini .rst-content h2 .headerlink:before,
.rst-content h2 .btn-mini .headerlink:before,
.btn-mini .rst-content h3 .headerlink:before,
.rst-content h3 .btn-mini .headerlink:before,
.btn-mini .rst-content h4 .headerlink:before,
.rst-content h4 .btn-mini .headerlink:before,
.btn-mini .rst-content h5 .headerlink:before,
.rst-content h5 .btn-mini .headerlink:before,
.btn-mini .rst-content h6 .headerlink:before,
.rst-content h6 .btn-mini .headerlink:before,
.btn-mini .rst-content dl dt .headerlink:before,
.rst-content dl dt .btn-mini .headerlink:before,
.btn-mini .rst-content p.caption .headerlink:before,
.rst-content p.caption .btn-mini .headerlink:before,
.btn-mini .rst-content tt.download span:first-child:before,
.rst-content tt.download .btn-mini span:first-child:before,
.btn-mini .rst-content code.download span:first-child:before,
.rst-content code.download .btn-mini span:first-child:before,
.btn-mini .icon:before {
  font-size: 14px;
  vertical-align: -15%
}

.wy-alert,
.rst-content .note,
.rst-content .attention,
.rst-content .caution,
.rst-content .danger,
.rst-content .error,
.rst-content .hint,
.rst-content .important,
.rst-content .tip,
.rst-content .warning,
.rst-content .seealso,
.rst-content .admonition-todo {
  padding: 12px;
  line-height: 24px;
  margin-bottom: 24px;
  background: #e7f2fa
}

.wy-alert-title,
.rst-content .admonition-title {
  color: #fff;
  font-weight: 700;
  display: block;
  color: #fff;
  background: #6ab0de;
  margin: -12px;
  padding: 6px 12px;
  margin-bottom: 12px
}

.wy-alert.wy-alert-danger,
.rst-content .wy-alert-danger.note,
.rst-content .wy-alert-danger.attention,
.rst-content .wy-alert-danger.caution,
.rst-content .danger,
.rst-content .error,
.rst-content .wy-alert-danger.hint,
.rst-content .wy-alert-danger.important,
.rst-content .wy-alert-danger.tip,
.rst-content .wy-alert-danger.warning,
.rst-content .wy-alert-danger.seealso,
.rst-content .wy-alert-danger.admonition-todo {
  background: #fdf3f2
}

.wy-alert.wy-alert-danger .wy-alert-title,
.rst-content .wy-alert-danger.note .wy-alert-title,
.rst-content .wy-alert-danger.attention .wy-alert-title,
.rst-content .wy-alert-danger.caution .wy-alert-title,
.rst-content .danger .wy-alert-title,
.rst-content .error .wy-alert-title,
.rst-content .wy-alert-danger.hint .wy-alert-title,
.rst-content .wy-alert-danger.important .wy-alert-title,
.rst-content .wy-alert-danger.tip .wy-alert-title,
.rst-content .wy-alert-danger.warning .wy-alert-title,
.rst-content .wy-alert-danger.seealso .wy-alert-title,
.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,
.wy-alert.wy-alert-danger .rst-content .admonition-title,
.rst-content .wy-alert.wy-alert-danger .admonition-title,
.rst-content .wy-alert-danger.note .admonition-title,
.rst-content .wy-alert-danger.attention .admonition-title,
.rst-content .wy-alert-danger.caution .admonition-title,
.rst-content .danger .admonition-title,
.rst-content .error .admonition-title,
.rst-content .wy-alert-danger.hint .admonition-title,
.rst-content .wy-alert-danger.important .admonition-title,
.rst-content .wy-alert-danger.tip .admonition-title,
.rst-content .wy-alert-danger.warning .admonition-title,
.rst-content .wy-alert-danger.seealso .admonition-title,
.rst-content .wy-alert-danger.admonition-todo .admonition-title {
  background: #f29f97
}

.wy-alert.wy-alert-warning,
.rst-content .wy-alert-warning.note,
.rst-content .attention,
.rst-content .caution,
.rst-content .wy-alert-warning.danger,
.rst-content .wy-alert-warning.error,
.rst-content .wy-alert-warning.hint,
.rst-content .wy-alert-warning.important,
.rst-content .wy-alert-warning.tip,
.rst-content .warning,
.rst-content .wy-alert-warning.seealso,
.rst-content .admonition-todo {
  background: #ffedcc
}

.wy-alert.wy-alert-warning .wy-alert-title,
.rst-content .wy-alert-warning.note .wy-alert-title,
.rst-content .attention .wy-alert-title,
.rst-content .caution .wy-alert-title,
.rst-content .wy-alert-warning.danger .wy-alert-title,
.rst-content .wy-alert-warning.error .wy-alert-title,
.rst-content .wy-alert-warning.hint .wy-alert-title,
.rst-content .wy-alert-warning.important .wy-alert-title,
.rst-content .wy-alert-warning.tip .wy-alert-title,
.rst-content .warning .wy-alert-title,
.rst-content .wy-alert-warning.seealso .wy-alert-title,
.rst-content .admonition-todo .wy-alert-title,
.wy-alert.wy-alert-warning .rst-content .admonition-title,
.rst-content .wy-alert.wy-alert-warning .admonition-title,
.rst-content .wy-alert-warning.note .admonition-title,
.rst-content .attention .admonition-title,
.rst-content .caution .admonition-title,
.rst-content .wy-alert-warning.danger .admonition-title,
.rst-content .wy-alert-warning.error .admonition-title,
.rst-content .wy-alert-warning.hint .admonition-title,
.rst-content .wy-alert-warning.important .admonition-title,
.rst-content .wy-alert-warning.tip .admonition-title,
.rst-content .warning .admonition-title,
.rst-content .wy-alert-warning.seealso .admonition-title,
.rst-content .admonition-todo .admonition-title {
  background: #f0b37e
}

.wy-alert.wy-alert-info,
.rst-content .note,
.rst-content .wy-alert-info.attention,
.rst-content .wy-alert-info.caution,
.rst-content .wy-alert-info.danger,
.rst-content .wy-alert-info.error,
.rst-content .wy-alert-info.hint,
.rst-content .wy-alert-info.important,
.rst-content .wy-alert-info.tip,
.rst-content .wy-alert-info.warning,
.rst-content .seealso,
.rst-content .wy-alert-info.admonition-todo {
  background: #e7f2fa
}

.wy-alert.wy-alert-info .wy-alert-title,
.rst-content .note .wy-alert-title,
.rst-content .wy-alert-info.attention .wy-alert-title,
.rst-content .wy-alert-info.caution .wy-alert-title,
.rst-content .wy-alert-info.danger .wy-alert-title,
.rst-content .wy-alert-info.error .wy-alert-title,
.rst-content .wy-alert-info.hint .wy-alert-title,
.rst-content .wy-alert-info.important .wy-alert-title,
.rst-content .wy-alert-info.tip .wy-alert-title,
.rst-content .wy-alert-info.warning .wy-alert-title,
.rst-content .seealso .wy-alert-title,
.rst-content .wy-alert-info.admonition-todo .wy-alert-title,
.wy-alert.wy-alert-info .rst-content .admonition-title,
.rst-content .wy-alert.wy-alert-info .admonition-title,
.rst-content .note .admonition-title,
.rst-content .wy-alert-info.attention .admonition-title,
.rst-content .wy-alert-info.caution .admonition-title,
.rst-content .wy-alert-info.danger .admonition-title,
.rst-content .wy-alert-info.error .admonition-title,
.rst-content .wy-alert-info.hint .admonition-title,
.rst-content .wy-alert-info.important .admonition-title,
.rst-content .wy-alert-info.tip .admonition-title,
.rst-content .wy-alert-info.warning .admonition-title,
.rst-content .seealso .admonition-title,
.rst-content .wy-alert-info.admonition-todo .admonition-title {
  background: #6ab0de
}

.wy-alert.wy-alert-success,
.rst-content .wy-alert-success.note,
.rst-content .wy-alert-success.attention,
.rst-content .wy-alert-success.caution,
.rst-content .wy-alert-success.danger,
.rst-content .wy-alert-success.error,
.rst-content .hint,
.rst-content .important,
.rst-content .tip,
.rst-content .wy-alert-success.warning,
.rst-content .wy-alert-success.seealso,
.rst-content .wy-alert-success.admonition-todo {
  background: #dbfaf4
}

.wy-alert.wy-alert-success .wy-alert-title,
.rst-content .wy-alert-success.note .wy-alert-title,
.rst-content .wy-alert-success.attention .wy-alert-title,
.rst-content .wy-alert-success.caution .wy-alert-title,
.rst-content .wy-alert-success.danger .wy-alert-title,
.rst-content .wy-alert-success.error .wy-alert-title,
.rst-content .hint .wy-alert-title,
.rst-content .important .wy-alert-title,
.rst-content .tip .wy-alert-title,
.rst-content .wy-alert-success.warning .wy-alert-title,
.rst-content .wy-alert-success.seealso .wy-alert-title,
.rst-content .wy-alert-success.admonition-todo .wy-alert-title,
.wy-alert.wy-alert-success .rst-content .admonition-title,
.rst-content .wy-alert.wy-alert-success .admonition-title,
.rst-content .wy-alert-success.note .admonition-title,
.rst-content .wy-alert-success.attention .admonition-title,
.rst-content .wy-alert-success.caution .admonition-title,
.rst-content .wy-alert-success.danger .admonition-title,
.rst-content .wy-alert-success.error .admonition-title,
.rst-content .hint .admonition-title,
.rst-content .important .admonition-title,
.rst-content .tip .admonition-title,
.rst-content .wy-alert-success.warning .admonition-title,
.rst-content .wy-alert-success.seealso .admonition-title,
.rst-content .wy-alert-success.admonition-todo .admonition-title {
  background: #1abc9c
}

.wy-alert.wy-alert-neutral,
.rst-content .wy-alert-neutral.note,
.rst-content .wy-alert-neutral.attention,
.rst-content .wy-alert-neutral.caution,
.rst-content .wy-alert-neutral.danger,
.rst-content .wy-alert-neutral.error,
.rst-content .wy-alert-neutral.hint,
.rst-content .wy-alert-neutral.important,
.rst-content .wy-alert-neutral.tip,
.rst-content .wy-alert-neutral.warning,
.rst-content .wy-alert-neutral.seealso,
.rst-content .wy-alert-neutral.admonition-todo {
  background: #f3f6f6
}

.wy-alert.wy-alert-neutral .wy-alert-title,
.rst-content .wy-alert-neutral.note .wy-alert-title,
.rst-content .wy-alert-neutral.attention .wy-alert-title,
.rst-content .wy-alert-neutral.caution .wy-alert-title,
.rst-content .wy-alert-neutral.danger .wy-alert-title,
.rst-content .wy-alert-neutral.error .wy-alert-title,
.rst-content .wy-alert-neutral.hint .wy-alert-title,
.rst-content .wy-alert-neutral.important .wy-alert-title,
.rst-content .wy-alert-neutral.tip .wy-alert-title,
.rst-content .wy-alert-neutral.warning .wy-alert-title,
.rst-content .wy-alert-neutral.seealso .wy-alert-title,
.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,
.wy-alert.wy-alert-neutral .rst-content .admonition-title,
.rst-content .wy-alert.wy-alert-neutral .admonition-title,
.rst-content .wy-alert-neutral.note .admonition-title,
.rst-content .wy-alert-neutral.attention .admonition-title,
.rst-content .wy-alert-neutral.caution .admonition-title,
.rst-content .wy-alert-neutral.danger .admonition-title,
.rst-content .wy-alert-neutral.error .admonition-title,
.rst-content .wy-alert-neutral.hint .admonition-title,
.rst-content .wy-alert-neutral.important .admonition-title,
.rst-content .wy-alert-neutral.tip .admonition-title,
.rst-content .wy-alert-neutral.warning .admonition-title,
.rst-content .wy-alert-neutral.seealso .admonition-title,
.rst-content .wy-alert-neutral.admonition-todo .admonition-title {
  color: #404040;
  background: #e1e4e5
}

.wy-alert.wy-alert-neutral a,
.rst-content .wy-alert-neutral.note a,
.rst-content .wy-alert-neutral.attention a,
.rst-content .wy-alert-neutral.caution a,
.rst-content .wy-alert-neutral.danger a,
.rst-content .wy-alert-neutral.error a,
.rst-content .wy-alert-neutral.hint a,
.rst-content .wy-alert-neutral.important a,
.rst-content .wy-alert-neutral.tip a,
.rst-content .wy-alert-neutral.warning a,
.rst-content .wy-alert-neutral.seealso a,
.rst-content .wy-alert-neutral.admonition-todo a {
  color: #008BF3
}

.wy-alert p:last-child,
.rst-content .note p:last-child,
.rst-content .attention p:last-child,
.rst-content .caution p:last-child,
.rst-content .danger p:last-child,
.rst-content .error p:last-child,
.rst-content .hint p:last-child,
.rst-content .important p:last-child,
.rst-content .tip p:last-child,
.rst-content .warning p:last-child,
.rst-content .seealso p:last-child,
.rst-content .admonition-todo p:last-child {
  margin-bottom: 0
}

.wy-tray-container {
  position: fixed;
  bottom: 0;
  left: 0;
  z-index: 600
}

.wy-tray-container li {
  display: block;
  width: 300px;
  background: transparent;
  color: #fff;
  text-align: center;
  box-shadow: 0 5px 5px 0 rgba(0,0,0,0.1);
  padding: 0 24px;
  min-width: 20%;
  opacity: 0;
  height: 0;
  line-height: 56px;
  overflow: hidden;
  -webkit-transition: all .3s ease-in;
  -moz-transition: all .3s ease-in;
  transition: all .3s ease-in
}

.wy-tray-container li.wy-tray-item-success {
  background: #27AE60
}

.wy-tray-container li.wy-tray-item-info {
  background: #2980B9
}

.wy-tray-container li.wy-tray-item-warning {
  background: #E67E22
}

.wy-tray-container li.wy-tray-item-danger {
  background: #E74C3C
}

.wy-tray-container li.on {
  opacity: 1;
  height: 56px
}

@media screen and (max-width: 768px) {
  .wy-tray-container {
    bottom: auto;
    top: 0;
    width: 100%
  }

  .wy-tray-container li {
    width: 100%
  }

}

button {
  font-size: 100%;
  margin: 0;
  vertical-align: baseline;
  *vertical-align: middle;
  cursor: pointer;
  line-height: normal;
  -webkit-appearance: button;
  *overflow: visible
}

button::-moz-focus-inner,
input::-moz-focus-inner {
  border: 0;
  padding: 0
}

button[disabled] {
  cursor: default
}

.btn {
  font-family: "Source Sans Pro","proxima-nova","Helvetica Neue",Arial,sans-serif;
  display: inline-block;
  padding: 10px 30px;
  margin-bottom: 0;
  font-weight: 400;
  text-align: center;
  vertical-align: middle;
  -ms-touch-action: manipulation;
  touch-action: manipulation;
  cursor: pointer;
  background-image: none;
  background-color: #4a90e2;
  border: 1px solid transparent;
  white-space: nowrap;
  color: rgba(255,255,255,0.95);
  border-radius: 3px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  outline: none
}

.btn-hover {
  background: #2e8ece;
  color: #fff
}

.btn:disabled {
  background-image: none;
  filter: progid: DXImageTransform.Microsoft.gradient(enabled=false);
  filter: alpha(opacity=40);
  opacity: .4;
  cursor: not-allowed;
  box-shadow: none
}

.btn-disabled {
  background-image: none;
  filter: progid: DXImageTransform.Microsoft.gradient(enabled=false);
  filter: alpha(opacity=40);
  opacity: .4;
  cursor: not-allowed;
  box-shadow: none
}

.btn-disabled:hover,
.btn-disabled:focus,
.btn-disabled:active {
  background-image: none;
  filter: progid: DXImageTransform.Microsoft.gradient(enabled=false);
  filter: alpha(opacity=40);
  opacity: .4;
  cursor: not-allowed;
  box-shadow: none
}

.btn::-moz-focus-inner {
  padding: 0;
  border: 0
}

.btn-small {
  font-size: 80%
}

.btn-info {
  background-color: #2980B9!important
}

.btn-info:hover {
  background-color: #2e8ece!important
}

.btn-neutral {
  font-size: 14px;
  color: #fff;
  font-weight: 300;
  /*background-color: #008bf3!important*/
}

.btn-success {
  background-color: #27AE60!important
}

.btn-success:hover {
  background-color: #295!important
}

.btn-danger {
  background-color: #E74C3C!important
}

.btn-danger:hover {
  background-color: #ea6153!important
}

.btn-warning {
  background-color: #E67E22!important
}

.btn-warning:hover {
  background-color: #e98b39!important
}

.btn-invert {
  background-color: #222
}

.btn-invert:hover {
  background-color: #2f2f2f!important
}

.btn-link {
  background-color: transparent!important;
  color: #2980B9;
  box-shadow: none;
  border-color: transparent!important
}

.btn-link:hover {
  background-color: transparent!important;
  color: #409ad5!important;
  box-shadow: none
}

.btn-link:active {
  background-color: transparent!important;
  color: #409ad5!important;
  box-shadow: none
}

.btn-link:visited {
  color: #9B59B6
}

.wy-btn-group .btn,
.wy-control .btn {
  vertical-align: middle
}

.wy-btn-group {
  margin-bottom: 24px;
  *zoom: 1
}

.wy-btn-group:before,
.wy-btn-group:after {
  display: table;
  content: ""
}

.wy-btn-group:after {
  clear: both
}

.wy-dropdown {
  position: relative;
  display: inline-block
}

.wy-dropdown-active .wy-dropdown-menu {
  display: block
}

.wy-dropdown-menu {
  position: absolute;
  left: 0;
  display: none;
  float: left;
  top: 100%;
  min-width: 100%;
  background: #fcfcfc;
  z-index: 100;
  border: solid 1px #cfd7dd;
  box-shadow: 0 2px 2px 0 rgba(0,0,0,0.1);
  padding: 12px
}

.wy-dropdown-menu>dd>a {
  display: block;
  clear: both;
  color: #404040;
  white-space: nowrap;
  font-size: 90%;
  padding: 0 12px;
  cursor: pointer
}

.wy-dropdown-menu>dd>a:hover {
  background: #2980B9;
  color: #fff
}

.wy-dropdown-menu>dd.divider {
  border-top: solid 1px #cfd7dd;
  margin: 6px 0
}

.wy-dropdown-menu>dd.search {
  padding-bottom: 12px
}

.wy-dropdown-menu>dd.search input[type="search"] {
  width: 100%
}

.wy-dropdown-menu>dd.call-to-action {
  background: #e3e3e3;
  text-transform: uppercase;
  font-weight: 500;
  font-size: 80%
}

.wy-dropdown-menu>dd.call-to-action:hover {
  background: #e3e3e3
}

.wy-dropdown-menu>dd.call-to-action .btn {
  color: #fff
}

.wy-dropdown.wy-dropdown-up .wy-dropdown-menu {
  bottom: 100%;
  top: auto;
  left: auto;
  right: 0
}

.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu {
  background: #fcfcfc;
  margin-top: 2px
}

.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a {
  padding: 6px 12px
}

.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover {
  background: #2980B9;
  color: #fff
}

.wy-dropdown.wy-dropdown-left .wy-dropdown-menu {
  right: 0;
  left: auto;
  text-align: right
}

.wy-dropdown-arrow:before {
  content: " ";
  border-bottom: 5px solid #f5f5f5;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  position: absolute;
  display: block;
  top: -4px;
  left: 50%;
  margin-left: -3px
}

.wy-dropdown-arrow.wy-dropdown-arrow-left:before {
  left: 11px
}

.wy-form-stacked select {
  display: block
}

.wy-form-aligned input,
.wy-form-aligned textarea,
.wy-form-aligned select,
.wy-form-aligned .wy-help-inline,
.wy-form-aligned label {
  display: inline-block;
  *display: inline;
  *zoom: 1;
  vertical-align: middle
}

.wy-form-aligned .wy-control-group>label {
  display: inline-block;
  vertical-align: middle;
  width: 10em;
  margin: 6px 12px 0 0;
  float: left
}

.wy-form-aligned .wy-control {
  float: left
}

.wy-form-aligned .wy-control label {
  display: block
}

.wy-form-aligned .wy-control select {
  margin-top: 6px
}

fieldset {
  border: 0;
  margin: 0;
  padding: 0
}

legend {
  display: block;
  width: 100%;
  border: 0;
  padding: 0;
  white-space: normal;
  margin-bottom: 24px;
  font-size: 150%;
  *margin-left: -7px
}

label {
  display: block;
  margin: 0 0 .3125em;
  color: #333;
  font-size: 90%
}

input,
select,
textarea {
  font-size: 100%;
  margin: 0;
  vertical-align: baseline;
  *vertical-align: middle
}

.wy-control-group {
  margin-bottom: 24px;
  *zoom: 1;
  max-width: 68em;
  margin-left: auto;
  margin-right: auto;
  *zoom: 1
}

.wy-control-group:before,
.wy-control-group:after {
  display: table;
  content: ""
}

.wy-control-group:after {
  clear: both
}

.wy-control-group:before,
.wy-control-group:after {
  display: table;
  content: ""
}

.wy-control-group:after {
  clear: both
}

.wy-control-group.wy-control-group-required>label:after {
  content: " *";
  color: #E74C3C
}

.wy-control-group .wy-form-full,
.wy-control-group .wy-form-halves,
.wy-control-group .wy-form-thirds {
  padding-bottom: 12px
}

.wy-control-group .wy-form-full select,
.wy-control-group .wy-form-halves select,
.wy-control-group .wy-form-thirds select {
  width: 100%
}

.wy-control-group .wy-form-full input[type="text"],
.wy-control-group .wy-form-full input[type="password"],
.wy-control-group .wy-form-full input[type="email"],
.wy-control-group .wy-form-full input[type="url"],
.wy-control-group .wy-form-full input[type="date"],
.wy-control-group .wy-form-full input[type="month"],
.wy-control-group .wy-form-full input[type="time"],
.wy-control-group .wy-form-full input[type="datetime"],
.wy-control-group .wy-form-full input[type="datetime-local"],
.wy-control-group .wy-form-full input[type="week"],
.wy-control-group .wy-form-full input[type="number"],
.wy-control-group .wy-form-full input[type="search"],
.wy-control-group .wy-form-full input[type="tel"],
.wy-control-group .wy-form-full input[type="color"],
.wy-control-group .wy-form-halves input[type="text"],
.wy-control-group .wy-form-halves input[type="password"],
.wy-control-group .wy-form-halves input[type="email"],
.wy-control-group .wy-form-halves input[type="url"],
.wy-control-group .wy-form-halves input[type="date"],
.wy-control-group .wy-form-halves input[type="month"],
.wy-control-group .wy-form-halves input[type="time"],
.wy-control-group .wy-form-halves input[type="datetime"],
.wy-control-group .wy-form-halves input[type="datetime-local"],
.wy-control-group .wy-form-halves input[type="week"],
.wy-control-group .wy-form-halves input[type="number"],
.wy-control-group .wy-form-halves input[type="search"],
.wy-control-group .wy-form-halves input[type="tel"],
.wy-control-group .wy-form-halves input[type="color"],
.wy-control-group .wy-form-thirds input[type="text"],
.wy-control-group .wy-form-thirds input[type="password"],
.wy-control-group .wy-form-thirds input[type="email"],
.wy-control-group .wy-form-thirds input[type="url"],
.wy-control-group .wy-form-thirds input[type="date"],
.wy-control-group .wy-form-thirds input[type="month"],
.wy-control-group .wy-form-thirds input[type="time"],
.wy-control-group .wy-form-thirds input[type="datetime"],
.wy-control-group .wy-form-thirds input[type="datetime-local"],
.wy-control-group .wy-form-thirds input[type="week"],
.wy-control-group .wy-form-thirds input[type="number"],
.wy-control-group .wy-form-thirds input[type="search"],
.wy-control-group .wy-form-thirds input[type="tel"],
.wy-control-group .wy-form-thirds input[type="color"] {
  width: 100%
}

.wy-control-group .wy-form-full {
  float: left;
  display: block;
  margin-right: 2.35765%;
  width: 100%;
  margin-right: 0
}

.wy-control-group .wy-form-full:last-child {
  margin-right: 0
}

.wy-control-group .wy-form-halves {
  float: left;
  display: block;
  margin-right: 2.35765%;
  width: 48.82117%
}

.wy-control-group .wy-form-halves:last-child {
  margin-right: 0
}

.wy-control-group .wy-form-halves:nth-of-type(2n) {
  margin-right: 0
}

.wy-control-group .wy-form-halves:nth-of-type(2n+1) {
  clear: left
}

.wy-control-group .wy-form-thirds {
  float: left;
  display: block;
  margin-right: 2.35765%;
  width: 31.76157%
}

.wy-control-group .wy-form-thirds:last-child {
  margin-right: 0
}

.wy-control-group .wy-form-thirds:nth-of-type(3n) {
  margin-right: 0
}

.wy-control-group .wy-form-thirds:nth-of-type(3n+1) {
  clear: left
}

.wy-control-group.wy-control-group-no-input .wy-control {
  margin: 6px 0 0;
  font-size: 90%
}

.wy-control-no-input {
  display: inline-block;
  margin: 6px 0 0;
  font-size: 90%
}

.wy-control-group.fluid-input input[type="text"],
.wy-control-group.fluid-input input[type="password"],
.wy-control-group.fluid-input input[type="email"],
.wy-control-group.fluid-input input[type="url"],
.wy-control-group.fluid-input input[type="date"],
.wy-control-group.fluid-input input[type="month"],
.wy-control-group.fluid-input input[type="time"],
.wy-control-group.fluid-input input[type="datetime"],
.wy-control-group.fluid-input input[type="datetime-local"],
.wy-control-group.fluid-input input[type="week"],
.wy-control-group.fluid-input input[type="number"],
.wy-control-group.fluid-input input[type="search"],
.wy-control-group.fluid-input input[type="tel"],
.wy-control-group.fluid-input input[type="color"] {
  width: 100%
}

.wy-form-message-inline {
  display: inline-block;
  padding-left: .3em;
  color: #666;
  vertical-align: middle;
  font-size: 90%
}

.wy-form-message {
  display: block;
  color: #999;
  font-size: 70%;
  margin-top: .3125em;
  font-style: italic
}

.wy-form-message p {
  font-size: inherit;
  font-style: italic;
  margin-bottom: 6px
}

.wy-form-message p:last-child {
  margin-bottom: 0
}

input {
  line-height: normal
}

input[type="button"],
input[type="reset"],
input[type="submit"] {
  -webkit-appearance: button;
  cursor: pointer;
  font-family: "Source Sans Pro","proxima-nova","Helvetica Neue",Arial,sans-serif;
  *overflow: visible
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="datetime"],
input[type="datetime-local"],
input[type="week"],
input[type="number"],
input[type="search"],
input[type="tel"],
input[type="color"] {
  -webkit-appearance: none;
  padding: 6px;
  display: inline-block;
  border: 1px solid #ccc;
  font-size: 80%;
  font-family: "Source Sans Pro","proxima-nova","Helvetica Neue",Arial,sans-serif;
  box-shadow: inset 0 1px 3px #ddd;
  border-radius: 0;
  -webkit-transition: border .3s linear;
  -moz-transition: border .3s linear;
  transition: border .3s linear
}

input[type="datetime-local"] {
  padding: .34375em .625em
}

input[disabled] {
  cursor: default
}

input[type="checkbox"],
input[type="radio"] {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  padding: 0;
  margin-right: .3125em;
  *height: 13px;
  *width: 13px
}

input[type="search"] {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box
}

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none
}

input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="time"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="week"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="color"]:focus {
  outline: 0;
  outline: thin dotted \9;
  border-color: #333
}

input.no-focus:focus {
  border-color: #ccc!important
}

input[type="file"]:focus,
input[type="radio"]:focus,
input[type="checkbox"]:focus {
  outline: thin dotted #333;
  outline: 1px auto #129FEA
}

input[type="text"][disabled],
input[type="password"][disabled],
input[type="email"][disabled],
input[type="url"][disabled],
input[type="date"][disabled],
input[type="month"][disabled],
input[type="time"][disabled],
input[type="datetime"][disabled],
input[type="datetime-local"][disabled],
input[type="week"][disabled],
input[type="number"][disabled],
input[type="search"][disabled],
input[type="tel"][disabled],
input[type="color"][disabled] {
  cursor: not-allowed;
  background-color: #fafafa
}

input:focus:invalid,
textarea:focus:invalid,
select:focus:invalid {
  color: #E74C3C;
  border: 1px solid #E74C3C
}

input:focus:invalid:focus,
textarea:focus:invalid:focus,
select:focus:invalid:focus {
  border-color: #E74C3C
}

input[type="file"]:focus:invalid:focus,
input[type="radio"]:focus:invalid:focus,
input[type="checkbox"]:focus:invalid:focus {
  outline-color: #E74C3C
}

input.wy-input-large {
  padding: 12px;
  font-size: 100%
}

textarea {
  overflow: auto;
  vertical-align: top;
  width: 100%;
  font-family: "Source Sans Pro","proxima-nova","Helvetica Neue",Arial,sans-serif
}

select,
textarea {
  padding: .5em .625em;
  display: inline-block;
  border: 1px solid #ccc;
  font-size: 80%;
  box-shadow: inset 0 1px 3px #ddd;
  -webkit-transition: border .3s linear;
  -moz-transition: border .3s linear;
  transition: border .3s linear
}

select {
  border: 1px solid #ccc;
  background-color: #fff
}

select[multiple] {
  height: auto
}

select:focus,
textarea:focus {
  outline: 0
}

select[disabled],
textarea[disabled],
input[readonly],
select[readonly],
textarea[readonly] {
  cursor: not-allowed;
  background-color: #fafafa
}

input[type="radio"][disabled],
input[type="checkbox"][disabled] {
  cursor: not-allowed
}

.wy-checkbox,
.wy-radio {
  margin: 6px 0;
  color: #404040;
  display: block
}

.wy-checkbox input,
.wy-radio input {
  vertical-align: baseline
}

.wy-form-message-inline {
  display: inline-block;
  *display: inline;
  *zoom: 1;
  vertical-align: middle
}

.wy-input-prefix,
.wy-input-suffix {
  white-space: nowrap;
  padding: 6px
}

.wy-input-prefix .wy-input-context,
.wy-input-suffix .wy-input-context {
  line-height: 27px;
  padding: 0 8px;
  display: inline-block;
  font-size: 80%;
  background-color: #f3f6f6;
  border: solid 1px #ccc;
  color: #999
}

.wy-input-suffix .wy-input-context {
  border-left: 0
}

.wy-input-prefix .wy-input-context {
  border-right: 0
}

.wy-switch {
  width: 36px;
  height: 12px;
  margin: 12px 0;
  position: relative;
  border-radius: 4px;
  background: #ccc;
  cursor: pointer;
  -webkit-transition: all .2s ease-in-out;
  -moz-transition: all .2s ease-in-out;
  transition: all .2s ease-in-out
}

.wy-switch:before {
  position: absolute;
  content: "";
  display: block;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  background: #999;
  left: -3px;
  top: -3px;
  -webkit-transition: all .2s ease-in-out;
  -moz-transition: all .2s ease-in-out;
  transition: all .2s ease-in-out
}

.wy-switch:after {
  content: "false";
  position: absolute;
  left: 48px;
  display: block;
  font-size: 12px;
  color: #ccc
}

.wy-switch.active {
  background: #1e8449
}

.wy-switch.active:before {
  left: 24px;
  background: #27AE60
}

.wy-switch.active:after {
  content: "true"
}

.wy-switch.disabled,
.wy-switch.active.disabled {
  cursor: not-allowed
}

.wy-control-group.wy-control-group-error .wy-form-message,
.wy-control-group.wy-control-group-error>label {
  color: #E74C3C
}

.wy-control-group.wy-control-group-error input[type="text"],
.wy-control-group.wy-control-group-error input[type="password"],
.wy-control-group.wy-control-group-error input[type="email"],
.wy-control-group.wy-control-group-error input[type="url"],
.wy-control-group.wy-control-group-error input[type="date"],
.wy-control-group.wy-control-group-error input[type="month"],
.wy-control-group.wy-control-group-error input[type="time"],
.wy-control-group.wy-control-group-error input[type="datetime"],
.wy-control-group.wy-control-group-error input[type="datetime-local"],
.wy-control-group.wy-control-group-error input[type="week"],
.wy-control-group.wy-control-group-error input[type="number"],
.wy-control-group.wy-control-group-error input[type="search"],
.wy-control-group.wy-control-group-error input[type="tel"],
.wy-control-group.wy-control-group-error input[type="color"] {
  border: solid 1px #E74C3C
}

.wy-control-group.wy-control-group-error textarea {
  border: solid 1px #E74C3C
}

.wy-inline-validate {
  white-space: nowrap
}

.wy-inline-validate .wy-input-context {
  padding: .5em .625em;
  display: inline-block;
  font-size: 80%
}

.wy-inline-validate.wy-inline-validate-success .wy-input-context {
  color: #27AE60
}

.wy-inline-validate.wy-inline-validate-danger .wy-input-context {
  color: #E74C3C
}

.wy-inline-validate.wy-inline-validate-warning .wy-input-context {
  color: #E67E22
}

.wy-inline-validate.wy-inline-validate-info .wy-input-context {
  color: #2980B9
}

.rotate-90 {
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  -o-transform: rotate(90deg);
  transform: rotate(90deg)
}

.rotate-180 {
  -webkit-transform: rotate(180deg);
  -moz-transform: rotate(180deg);
  -ms-transform: rotate(180deg);
  -o-transform: rotate(180deg);
  transform: rotate(180deg)
}

.rotate-270 {
  -webkit-transform: rotate(270deg);
  -moz-transform: rotate(270deg);
  -ms-transform: rotate(270deg);
  -o-transform: rotate(270deg);
  transform: rotate(270deg)
}

.mirror {
  -webkit-transform: scaleX(-1);
  -moz-transform: scaleX(-1);
  -ms-transform: scaleX(-1);
  -o-transform: scaleX(-1);
  transform: scaleX(-1)
}

.mirror.rotate-90 {
  -webkit-transform: scaleX(-1) rotate(90deg);
  -moz-transform: scaleX(-1) rotate(90deg);
  -ms-transform: scaleX(-1) rotate(90deg);
  -o-transform: scaleX(-1) rotate(90deg);
  transform: scaleX(-1) rotate(90deg)
}

.mirror.rotate-180 {
  -webkit-transform: scaleX(-1) rotate(180deg);
  -moz-transform: scaleX(-1) rotate(180deg);
  -ms-transform: scaleX(-1) rotate(180deg);
  -o-transform: scaleX(-1) rotate(180deg);
  transform: scaleX(-1) rotate(180deg)
}

.mirror.rotate-270 {
  -webkit-transform: scaleX(-1) rotate(270deg);
  -moz-transform: scaleX(-1) rotate(270deg);
  -ms-transform: scaleX(-1) rotate(270deg);
  -o-transform: scaleX(-1) rotate(270deg);
  transform: scaleX(-1) rotate(270deg)
}

@media only screen and (max-width: 480px) {
  .wy-form button[type="submit"] {
    margin: .7em 0 0
  }

  .wy-form input[type="text"],
  .wy-form input[type="password"],
  .wy-form input[type="email"],
  .wy-form input[type="url"],
  .wy-form input[type="date"],
  .wy-form input[type="month"],
  .wy-form input[type="time"],
  .wy-form input[type="datetime"],
  .wy-form input[type="datetime-local"],
  .wy-form input[type="week"],
  .wy-form input[type="number"],
  .wy-form input[type="search"],
  .wy-form input[type="tel"],
  .wy-form input[type="color"] {
    margin-bottom: .3em;
    display: block
  }

  .wy-form label {
    margin-bottom: .3em;
    display: block
  }

  .wy-form input[type="password"],
  .wy-form input[type="email"],
  .wy-form input[type="url"],
  .wy-form input[type="date"],
  .wy-form input[type="month"],
  .wy-form input[type="time"],
  .wy-form input[type="datetime"],
  .wy-form input[type="datetime-local"],
  .wy-form input[type="week"],
  .wy-form input[type="number"],
  .wy-form input[type="search"],
  .wy-form input[type="tel"],
  .wy-form input[type="color"] {
    margin-bottom: 0
  }

  .wy-form-aligned .wy-control-group label {
    margin-bottom: .3em;
    text-align: left;
    display: block;
    width: 100%
  }

  .wy-form-aligned .wy-control {
    margin: 1.5em 0 0
  }

  .wy-form .wy-help-inline,
  .wy-form-message-inline,
  .wy-form-message {
    display: block;
    font-size: 80%;
    padding: 6px 0
  }

}

@media screen and (max-width: 768px) {
  .tablet-hide {
    display: none
  }

}

@media screen and (max-width: 480px) {
  .mobile-hide {
    display: none
  }

}

.float-left {
  float: left
}

.float-right {
  float: right
}

.full-width {
  width: 100%
}

.wy-table,
.rst-content table.docutils,
.rst-content table.field-list {
  border-collapse: collapse;
  border-spacing: 0;
  empty-cells: show;
  margin-bottom: 24px
}

.wy-table caption,
.rst-content table.docutils caption,
.rst-content table.field-list caption {
  color: #000;
  font: italic 85%/1 arial,sans-serif;
  padding: 1em 0;
  text-align: center
}

.wy-table td,
.rst-content table.docutils td,
.rst-content table.field-list td,
.wy-table th,
.rst-content table.docutils th,
.rst-content table.field-list th {
  font-size: 16px;
  margin: 0;
  overflow: visible;
  padding: 6px 13px
}

.wy-table td:first-child,
.rst-content table.docutils td:first-child,
.rst-content table.field-list td:first-child,
.wy-table th:first-child,
.rst-content table.docutils th:first-child,
.rst-content table.field-list th:first-child {
  border-left-width: 0
}

.wy-table thead,
.rst-content table.docutils thead,
.rst-content table.field-list thead {
  color: #000;
  text-align: center;
  vertical-align: bottom;
  white-space: nowrap
}

.wy-table thead th,
.rst-content table.docutils thead th,
.rst-content table.field-list thead th {
  font-weight: 700;
  border-bottom: solid 1px #ddd;
}

.wy-table td,
.rst-content table.docutils td,
.rst-content table.field-list td {
  background-color: transparent;
  vertical-align: middle
}

.wy-table td p,
.rst-content table.docutils td p,
.rst-content table.field-list td p {
  line-height: 18px
}

.wy-table td p:last-child,
.rst-content table.docutils td p:last-child,
.rst-content table.field-list td p:last-child {
  margin-bottom: 0
}

.wy-table .wy-table-cell-min,
.rst-content table.docutils .wy-table-cell-min,
.rst-content table.field-list .wy-table-cell-min {
  width: 1%;
  padding-right: 0
}

.wy-table .wy-table-cell-min input[type=checkbox],
.rst-content table.docutils .wy-table-cell-min input[type=checkbox],
.rst-content table.field-list .wy-table-cell-min input[type=checkbox],
.wy-table .wy-table-cell-min input[type=checkbox],
.rst-content table.docutils .wy-table-cell-min input[type=checkbox],
.rst-content table.field-list .wy-table-cell-min input[type=checkbox] {
  margin: 0
}

.wy-table-secondary {
  color: gray;
  font-size: 90%
}

.wy-table-tertiary {
  color: gray;
  font-size: 80%
}

.wy-table-odd td,
.wy-table-striped tr:nth-child(2n-1) td,
.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
  background-color: #fcfcfc;
}

.wy-table-odd td,
.wy-table-striped tr:nth-child(2n) td,
.rst-content table.docutils:not(.field-list) tr:nth-child(2n) td {
  background-color: #f8f8f8;
}

.wy-table-backed {
  background-color: #f8f8f8;
}

.wy-table-bordered-all,
.rst-content table.docutils {
  border: 1px solid #ddd;
  line-height: 24px;
}

.wy-table-bordered-all td,
.rst-content table.docutils td {
  border-bottom: 1px solid #ddd;
  border-left: 1px solid #ddd;
}

.wy-table-bordered-all tbody>tr:last-child td,
.rst-content table.docutils tbody>tr:last-child td {
  border-bottom-width: 0
}

.wy-table-bordered {
  border: 1px solid #ddd;
}

.wy-table-bordered-rows td {
  border-bottom: 1px solid #ddd;
}

.wy-table-bordered-rows tbody>tr:last-child td {
  border-bottom-width: 0
}

.wy-table-horizontal tbody>tr:last-child td {
  border-bottom-width: 0
}

.wy-table-horizontal td,
.wy-table-horizontal th {
  border-width: 0 0 1px;
  border-bottom: 1px solid #ddd;
}

.wy-table-horizontal tbody>tr:last-child td {
  border-bottom-width: 0
}

.wy-table-responsive {
  margin-bottom: 24px;
  max-width: 100%;
  overflow: auto
}

.wy-table-responsive table {
  margin-bottom: 0!important
}

.wy-table-responsive table td,
.wy-table-responsive table th {
  white-space: nowrap
}

a {
  text-decoration: none;
  cursor: pointer
}

html {
  height: 100%;
  overflow-x: hidden
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  font-weight: 400;
  color: #333;
  min-height: 100%;
  overflow-x: hidden;
  background: #edf0f2
}

.wy-text-left {
  text-align: left
}

.wy-text-center {
  text-align: center
}

.wy-text-right {
  text-align: right
}

.wy-text-large {
  font-size: 120%
}

.wy-text-normal {
  font-size: 100%
}

.wy-text-small,
small {
  font-size: 80%
}

.wy-text-strike {
  text-decoration: line-through
}

.wy-text-warning {
  color: #E67E22!important
}

a.wy-text-warning:hover {
  color: #eb9950!important
}

.wy-text-info {
  color: #2980B9!important
}

a.wy-text-info:hover {
  color: #409ad5!important
}

.wy-text-success {
  color: #27AE60!important
}

a.wy-text-success:hover {
  color: #36d278!important
}

.wy-text-danger {
  color: #E74C3C!important
}

a.wy-text-danger:hover {
  color: #ed7669!important
}

.wy-text-neutral {
  color: #404040!important
}

a.wy-text-neutral:hover {
  color: #595959!important
}

.h1,
.h2,
.h3,
.h4,
.h5,
.h6,
h1,
h2,
h3,
h4,
h5,
h6,
legend {
  margin-top: 0;
  font-weight: 700;
  font-family: "Source Sans Pro","ff-tisa-web-pro","Georgia",Arial,sans-serif;
  font-style: normal
}

p {
  line-height: 24px;
  margin: 0;
  font-size: 16px;
  margin-bottom: 24px
}

h1,
.h1 {
  font-size: 175%
}

h2,
.h2 {
  font-size: 150%
}

h3,
.h3 {
  font-size: 125%
}

h4,
.h4 {
  font-size: 115%
}

h5,
.h5 {
  font-size: 110%
}

h6,
.h6 {
  font-size: 100%
}

hr {
  display: block;
  height: 1px;
  border: 0;
  border-top: 1px solid #e1e4e5;
  margin: 24px 0;
  padding: 0
}

code,
.rst-content tt,
.rst-content code {
  max-width: 100%;
  background: #fff;
  border: solid 1px #e1e4e5;
  font-size: 75%;
  padding: 0 5px;
  font-family: "Source Code Pro","Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace;
  color: #E74C3C;
  overflow-x: auto
}

code.code-large,
.rst-content tt.code-large {
  font-size: 90%
}

.wy-plain-list-disc,
.rst-content .section ul,
.rst-content .toctree-wrapper ul,
article ul {
  list-style: disc;
  line-height: 24px;
  margin-bottom: 24px
}

.wy-plain-list-disc li,
.rst-content .section ul li,
.rst-content .toctree-wrapper ul li,
article ul li {
  list-style: disc;
  margin-left: 24px
}

.wy-plain-list-disc li p:last-child,
.rst-content .section ul li p:last-child,
.rst-content .toctree-wrapper ul li p:last-child,
article ul li p:last-child {
  margin-bottom: 0
}

.wy-plain-list-disc li ul,
.rst-content .section ul li ul,
.rst-content .toctree-wrapper ul li ul,
article ul li ul {
  margin-bottom: 0
}

.wy-plain-list-disc li li,
.rst-content .section ul li li,
.rst-content .toctree-wrapper ul li li,
article ul li li {
  list-style: circle
}

.wy-plain-list-disc li li li,
.rst-content .section ul li li li,
.rst-content .toctree-wrapper ul li li li,
article ul li li li {
  list-style: square
}

.wy-plain-list-disc li ol li,
.rst-content .section ul li ol li,
.rst-content .toctree-wrapper ul li ol li,
article ul li ol li {
  list-style: decimal
}

.wy-plain-list-decimal,
.rst-content .section ol,
.rst-content ol.arabic,
article ol {
  list-style: decimal;
  line-height: 24px;
  margin-bottom: 24px
}

.wy-plain-list-decimal li,
.rst-content .section ol li,
.rst-content ol.arabic li,
article ol li {
  list-style: decimal;
  margin-left: 24px
}

.wy-plain-list-decimal li p:last-child,
.rst-content .section ol li p:last-child,
.rst-content ol.arabic li p:last-child,
article ol li p:last-child {
  margin-bottom: 0
}

.wy-plain-list-decimal li ul,
.rst-content .section ol li ul,
.rst-content ol.arabic li ul,
article ol li ul {
  margin-bottom: 0
}

.wy-plain-list-decimal li ul li,
.rst-content .section ol li ul li,
.rst-content ol.arabic li ul li,
article ol li ul li {
  list-style: disc
}


footer {
  color: #999
}

footer p {
  margin-bottom: 12px
}

.rst-footer-buttons {
  *zoom: 1
}

.rst-footer-buttons:before,
.rst-footer-buttons:after {
  display: table;
  content: ""
}

.rst-footer-buttons:after {
  clear: both
}

#search-results .search li {
  margin-bottom: 24px;
  border-bottom: solid 1px #e1e4e5;
  padding-bottom: 24px
}

#search-results .search li:first-child {
  border-top: solid 1px #e1e4e5;
  padding-top: 24px
}

#search-results .search li a {
  font-size: 120%;
  margin-bottom: 12px;
  display: inline-block
}

#search-results .context {
  color: gray;
  font-size: 90%
}



@media print {
  .rst-versions,
  footer,
  .wy-nav-side {
    display: none
  }

  .wy-nav-content-wrap {
    margin-left: 0
  }

}

.rst-versions {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 300px;
  color: #fcfcfc;
  background: #1f1d1d;
  border-top: solid 10px #343131;
  font-family: "Source Sans Pro","proxima-nova","Helvetica Neue",Arial,sans-serif;
  z-index: 400
}

.rst-versions a {
  color: #2980B9;
  text-decoration: none
}

.rst-versions .rst-badge-small {
  display: none
}

.rst-versions .rst-current-version {
  padding: 12px;
  background-color: #272525;
  display: block;
  text-align: right;
  font-size: 90%;
  cursor: pointer;
  color: #27AE60;
  *zoom: 1
}

.rst-versions .rst-current-version:before,
.rst-versions .rst-current-version:after {
  display: table;
  content: ""
}

.rst-versions .rst-current-version:after {
  clear: both
}

.rst-versions .rst-current-version .fa,
.rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand,
.wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand,
.rst-versions .rst-current-version .rst-content .admonition-title,
.rst-content .rst-versions .rst-current-version .admonition-title,
.rst-versions .rst-current-version .rst-content h1 .headerlink,
.rst-content h1 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content h2 .headerlink,
.rst-content h2 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content h3 .headerlink,
.rst-content h3 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content h4 .headerlink,
.rst-content h4 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content h5 .headerlink,
.rst-content h5 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content h6 .headerlink,
.rst-content h6 .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content dl dt .headerlink,
.rst-content dl dt .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content p.caption .headerlink,
.rst-content p.caption .rst-versions .rst-current-version .headerlink,
.rst-versions .rst-current-version .rst-content tt.download span:first-child,
.rst-content tt.download .rst-versions .rst-current-version span:first-child,
.rst-versions .rst-current-version .rst-content code.download span:first-child,
.rst-content code.download .rst-versions .rst-current-version span:first-child,
.rst-versions .rst-current-version .icon {
  color: #fcfcfc
}

.rst-versions .rst-current-version .fa-book,
.rst-versions .rst-current-version .icon-book {
  float: left
}

.rst-versions .rst-current-version .icon-book {
  float: left
}

.rst-versions .rst-current-version.rst-out-of-date {
  background-color: #E74C3C;
  color: #fff
}

.rst-versions .rst-current-version.rst-active-old-version {
  background-color: #F1C40F;
  color: #000
}

.rst-versions.shift-up .rst-other-versions {
  display: block
}

.rst-versions .rst-other-versions {
  font-size: 90%;
  padding: 12px;
  color: gray;
  display: none
}

.rst-versions .rst-other-versions hr {
  display: block;
  height: 1px;
  border: 0;
  margin: 20px 0;
  padding: 0;
  border-top: solid 1px #413d3d
}

.rst-versions .rst-other-versions dd {
  display: inline-block;
  margin: 0
}

.rst-versions .rst-other-versions dd a {
  display: inline-block;
  padding: 6px;
  color: #fcfcfc
}

.rst-versions.rst-badge {
  width: auto;
  bottom: 20px;
  right: 20px;
  left: auto;
  border: none;
  max-width: 300px
}

.rst-versions.rst-badge .icon-book {
  float: none
}

.rst-versions.rst-badge .fa-book,
.rst-versions.rst-badge .icon-book {
  float: none
}

.rst-versions.rst-badge.shift-up .rst-current-version {
  text-align: right
}

.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,
.rst-versions.rst-badge.shift-up .rst-current-version .icon-book {
  float: left
}

.rst-versions.rst-badge.shift-up .rst-current-version .icon-book {
  float: left
}

.rst-versions.rst-badge .rst-current-version {
  width: auto;
  height: 30px;
  line-height: 30px;
  padding: 0 6px;
  display: block;
  text-align: center
}

@media screen and (max-width: 768px) {
  .rst-versions {
    width: 85%;
    display: none
  }

  .rst-versions.shift {
    display: block
  }

  img {
    width: 100%;
    height: auto
  }

}

.rst-content img {
  max-width: 100%;
  height: auto!important
}

.rst-content div.figure {
  margin-bottom: 24px
}

.rst-content div.figure.align-center {
  text-align: center
}

.rst-content .section>img,
.rst-content .section>a>img {
  margin-bottom: 24px
}

.rst-content blockquote {
  margin-left: 24px;
  line-height: 24px;
  margin-bottom: 24px
}

.rst-content .note .last,
.rst-content .attention .last,
.rst-content .caution .last,
.rst-content .danger .last,
.rst-content .error .last,
.rst-content .hint .last,
.rst-content .important .last,
.rst-content .tip .last,
.rst-content .warning .last,
.rst-content .seealso .last,
.rst-content .admonition-todo .last {
  margin-bottom: 0
}

.rst-content .admonition-title:before {
  margin-right: 4px
}

.rst-content .admonition table {
  border-color: rgba(0,0,0,0.1)
}

.rst-content .admonition table td,
.rst-content .admonition table th {
  background: transparent!important;
  border-color: rgba(0,0,0,0.1)!important
}

.rst-content .section ol.loweralpha,
.rst-content .section ol.loweralpha li {
  list-style: lower-alpha
}

.rst-content .section ol.upperalpha,
.rst-content .section ol.upperalpha li {
  list-style: upper-alpha
}

.rst-content .section ol p,
.rst-content .section ul p {
  margin-bottom: 12px
}

.rst-content .line-block {
  margin-left: 24px
}

.rst-content .topic-title {
  font-weight: 700;
  margin-bottom: 12px
}

.rst-content .toc-backref {
  color: #404040
}

.rst-content .align-right {
  float: right;
  margin: 0 0 24px 24px
}

.rst-content .align-left {
  float: left;
  margin: 0 24px 24px 0
}

.rst-content .align-center {
  margin: auto;
  display: block
}

.rst-content h1 .headerlink,
.rst-content h2 .headerlink,
.rst-content h3 .headerlink,
.rst-content h4 .headerlink,
.rst-content h5 .headerlink,
.rst-content h6 .headerlink,
.rst-content dl dt .headerlink,
.rst-content p.caption .headerlink {
  display: none;
  visibility: hidden;
  font-size: 14px
}

.rst-content h1 .headerlink:after,
.rst-content h2 .headerlink:after,
.rst-content h3 .headerlink:after,
.rst-content h4 .headerlink:after,
.rst-content h5 .headerlink:after,
.rst-content h6 .headerlink:after,
.rst-content dl dt .headerlink:after,
.rst-content p.caption .headerlink:after {
  visibility: visible;
  content: "";
  font-family: FontAwesome;
  display: inline-block
}

.rst-content h1:hover .headerlink,
.rst-content h2:hover .headerlink,
.rst-content h3:hover .headerlink,
.rst-content h4:hover .headerlink,
.rst-content h5:hover .headerlink,
.rst-content h6:hover .headerlink,
.rst-content dl dt:hover .headerlink,
.rst-content p.caption:hover .headerlink {
  display: inline-block
}

.rst-content .sidebar {
  float: right;
  width: 40%;
  display: block;
  margin: 0 0 24px 24px;
  padding: 24px;
  background: #f3f6f6;
  border: solid 1px #e1e4e5
}

.rst-content .sidebar p,
.rst-content .sidebar ul,
.rst-content .sidebar dl {
  font-size: 90%
}

.rst-content .sidebar .last {
  margin-bottom: 0
}

.rst-content .sidebar .sidebar-title {
  display: block;
  font-family: "Source Sans Pro","ff-tisa-web-pro","Georgia",Arial,sans-serif;
  font-weight: 700;
  background: #e1e4e5;
  padding: 6px 12px;
  margin: -24px;
  margin-bottom: 24px;
  font-size: 100%
}

.rst-content .highlighted {
  background: #F1C40F;
  display: inline-block;
  font-weight: 700;
  padding: 0 6px
}

.rst-content .footnote-reference,
.rst-content .citation-reference {
  vertical-align: super;
  font-size: 90%
}

.rst-content table.docutils.citation,
.rst-content table.docutils.footnote {
  background: none;
  border: none;
  color: #999
}

.rst-content table.docutils.citation td,
.rst-content table.docutils.citation tr,
.rst-content table.docutils.footnote td,
.rst-content table.docutils.footnote tr {
  border: none;
  background-color: transparent!important;
  white-space: normal
}

.rst-content table.docutils.citation td.label,
.rst-content table.docutils.footnote td.label {
  padding-left: 0;
  padding-right: 0;
  vertical-align: top
}

.rst-content table.field-list {
  border: none
}

.rst-content table.field-list td {
  border: none;
  padding-top: 5px
}

.rst-content table.field-list td>strong {
  display: inline-block;
  margin-top: 3px
}

.rst-content table.field-list .field-name {
  padding-right: 10px;
  text-align: left;
  white-space: nowrap
}

.rst-content table.field-list .field-body {
  text-align: left;
  padding-left: 0
}

.rst-content tt,
.rst-content tt,
.rst-content code {
  color: #000
}

.rst-content tt big,
.rst-content tt em,
.rst-content tt big,
.rst-content code big,
.rst-content tt em,
.rst-content code em {
  font-size: 100%!important;
  line-height: normal
}

.rst-content tt .xref,
a .rst-content tt,
.rst-content tt .xref,
.rst-content code .xref,
a .rst-content tt,
a .rst-content code {
  font-weight: 700
}

.rst-content a tt,
.rst-content a tt,
.rst-content a code {
  color: #2980B9
}

.rst-content dl {
  margin-bottom: 24px
}

.rst-content dl dt {
  font-weight: 700
}

.rst-content dl p,
.rst-content dl table,
.rst-content dl ul,
.rst-content dl ol {
  margin-bottom: 12px!important
}

.rst-content dl dd {
  margin: 0 0 12px 24px
}

.rst-content dl:not(.docutils) {
  margin-bottom: 24px
}

.rst-content dl:not(.docutils) dt {
  display: inline-block;
  margin: 6px 0;
  font-size: 90%;
  line-height: normal;
  background: #e7f2fa;
  color: #2980B9;
  border-top: solid 3px #6ab0de;
  padding: 6px;
  position: relative
}

.rst-content dl:not(.docutils) dt:before {
  color: #6ab0de
}

.rst-content dl:not(.docutils) dt .headerlink {
  color: #404040;
  font-size: 100%!important
}

.rst-content dl:not(.docutils) dl dt {
  margin-bottom: 6px;
  border: none;
  border-left: solid 3px #ccc;
  background: #f0f0f0;
  color: gray
}

.rst-content dl:not(.docutils) dl dt .headerlink {
  color: #404040;
  font-size: 100%!important
}

.rst-content dl:not(.docutils) dt:first-child {
  margin-top: 0
}

.rst-content dl:not(.docutils) tt,
.rst-content dl:not(.docutils) tt,
.rst-content dl:not(.docutils) code {
  font-weight: 700
}

.rst-content dl:not(.docutils) tt.descname,
.rst-content dl:not(.docutils) tt.descclassname,
.rst-content dl:not(.docutils) tt.descname,
.rst-content dl:not(.docutils) code.descname,
.rst-content dl:not(.docutils) tt.descclassname,
.rst-content dl:not(.docutils) code.descclassname {
  background-color: transparent;
  border: none;
  padding: 0;
  font-size: 100%!important
}

.rst-content dl:not(.docutils) tt.descname,
.rst-content dl:not(.docutils) tt.descname,
.rst-content dl:not(.docutils) code.descname {
  font-weight: 700
}

.rst-content dl:not(.docutils) .optional {
  display: inline-block;
  padding: 0 4px;
  color: #000;
  font-weight: 700
}

.rst-content dl:not(.docutils) .property {
  display: inline-block;
  padding-right: 8px
}

.rst-content .viewcode-link,
.rst-content .viewcode-back {
  display: inline-block;
  color: #27AE60;
  font-size: 80%;
  padding-left: 24px
}

.rst-content .viewcode-back {
  display: block;
  float: right
}

.rst-content p.rubric {
  margin-bottom: 12px;
  font-weight: 700
}

.rst-content tt.download,
.rst-content code.download {
  background: inherit;
  padding: inherit;
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  border: inherit;
  white-space: inherit
}

.rst-content tt.download span:first-child:before,
.rst-content code.download span:first-child:before {
  margin-right: 4px
}

@media screen and (max-width: 480px) {
  .rst-content .sidebar {
    width: 100%
  }

}

span[id*='MathJax-Span'] {
  color: #404040
}

.math {
  text-align: center
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 100;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-ExtraLight.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: italic;
  font-weight: 100;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-ExtraLightItalic.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 300;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-Light.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: italic;
  font-weight: 300;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-LightItalic.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 400;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-Regular.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: italic;
  font-weight: 400;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-Italic.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 500;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-Semibold.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: italic;
  font-weight: 500;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-SemiboldItalic.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 700;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-Bold.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Sans Pro';
  font-style: italic;
  font-weight: 700;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_sans_pro/SourceSansPro-BoldItalic.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Code Pro';
  font-style: normal;
  font-weight: 300;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_code_pro/SourceCodePro-Light.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Code Pro';
  font-style: normal;
  font-weight: 400;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_code_pro/SourceCodePro-Regular.ttf) format("truetype")
}

@font-face {
  font-family: 'Source Code Pro';
  font-style: normal;
  font-weight: 500;
  src: url(https://cdn.crashlytics.io/static_assets/web/typefaces/source_code_pro/SourceCodePro-Medium.ttf) format("truetype")
}

================================================
FILE: docs/css/goreplay.css
================================================
code {
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace !important;
  border-bottom-left-radius: 3px;
  border-bottom-right-radius: 3px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  background-color: #f7f7f7 !important;
  color: #333 !important;
  font-size: 14px !important;
  border: none !important;
  padding: 5px !important;
}

pre > code {
  line-height: 20px;
  padding: 16px !important;
}

blockquote {
  color: #777 !important;
  border-left: 4px solid rgb(221, 221, 221);
  padding-left: 16px;
  padding-right: 16px;
  margin-left: 0px !important;
}

/* Visited links purple is not a good idea */
a:visited {
  color: #008BF3;
}

a {
  color: #008BF3;
}

h3, h4, h5, h6 {
  color: #333 !important;
}

.rst-versions {
  display: none !important;
}

/* The next and previous button we don't need */
.rst-footer-buttons {
  display: none;
}

/* Foldable parts */
details > * {
  margin-left: 20px;
}
details > summary {
  margin-left: 0px; /* To overwrite the margin from above */

  font-size: 120%;
  cursor: pointer
}

/* Fix the design not having the correct spacing */
.wy-menu-vertical .subnav li.current > a {
  padding: 0.4045em 2.427em;
}

.toctree-l3 {
  padding-left: 1.0em;
}

footer .fastlane {
  margin: 20px 0;
}

footer .fastlane iframe {
  vertical-align: middle;
}

/* Custom Syntax highlighting to look more like GitHub.com */
.hljs-symbol {
  color: #0086b3;
}

.hljs-keyword {
  font-weight: normal;
  color: #a71d5d;
}

.hljs-string {
  color: #183691;
}

/* Header Anchors */
/* From https://github.com/facelessuser/pymdown-extensions/blob/bf18d0635e9d91b0f98eacdcaa10f26e0ace0f20/doc_theme/css/theme_custom.css#L322-L395 */
.rst-content .headeranchor-link {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  display: block;
  padding-right: 6px;
  padding-left: 30px;
  margin-left: -30px;
}

.rst-content .headeranchor-link:focus {
  outline: none;
}

.rst-content h1,
.rst-content h2,
.rst-content h3,
.rst-content h4,
.rst-content h5,
.rst-content h6 {
  position: relative;
}

.rst-content h1 .headeranchor,
.rst-content h2 .headeranchor,
.rst-content h3 .headeranchor,
.rst-content h4 .headeranchor,
.rst-content h5 .headeranchor,
.rst-content h6 .headeranchor {
  display: none;
  color: #000;
  vertical-align: middle;
}

.rst-content h1:hover .headeranchor-link,
.rst-content h2:hover .headeranchor-link,
.rst-content h3:hover .headeranchor-link,
.rst-content h4:hover .headeranchor-link,
.rst-content h5:hover .headeranchor-link,
.rst-content h6:hover .headeranchor-link {
  height: 1em;
  padding-left: 8px;
  margin-left: -30px;
  text-decoration: none;
}

.rst-content h1:hover .headeranchor-link .headeranchor,
.rst-content h2:hover .headeranchor-link .headeranchor,
.rst-content h3:hover .headeranchor-link .headeranchor,
.rst-content h4:hover .headeranchor-link .headeranchor,
.rst-content h5:hover .headeranchor-link .headeranchor,
.rst-content h6:hover .headeranchor-link .headeranchor {
  display: inline-block;
}

.rst-content .headeranchor {
  font: normal normal 16px FontAwesome;
  line-height: 1;
  display: inline-block;
  text-decoration: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.rst-content .headeranchor:before {
  content: '\f0c1';
}

/* index.md badges */
@media screen and (max-width: 768px) {
  .badge img {
    width: auto;
  }
}

================================================
FILE: docs/css/sidenav.css
================================================
.wy-affix {
  position: fixed;
  top: 1.618em;
}

.wy-menu a:hover {
  text-decoration: none;
}

.wy-menu-vertical header,
.wy-menu-vertical p.caption {
  height: 32px;
  display: inline-block;
  line-height: 32px;
  padding: 0 1.618em;
  margin-bottom: 0;
  margin-top: 14px;
  display: block;
  font-weight: 700;
  text-transform: uppercase;
  font-size: 85%;
  color: #ccc;
  white-space: nowrap;
}

.wy-menu-vertical span {
  color: #666;
}

.wy-menu-vertical ul {
  margin-bottom: 0;
}

.wy-menu-vertical li.divide-top {
  border-top: solid 1px #404040;
}

.wy-menu-vertical li.divide-bottom {
  border-bottom: solid 1px #404040;
}

.wy-menu-vertical li.current {
  background-color: #e5e5e5;
}

.wy-menu-vertical li.current a {
  color: rgba(0, 93, 255, 0.7);
  border-right: none;
}

.wy-menu-vertical li.current a:hover {
  color: rgba(0, 93, 255, 0.9);
}

.wy-menu-vertical li code,
.wy-menu-vertical li .rst-content tt,
.rst-content .wy-menu-vertical li tt {
  border: none;
  background: inherit;
  color: inherit;
  padding-left: 0;
  padding-right: 0
}

.wy-menu-vertical li span.toctree-expand {
  display: block;
  float: left;
  margin-left: -1.2em;
  font-size: .8em;
  line-height: 1.6em;
  color: #999;
}

.wy-menu-vertical li.on a,
.wy-menu-vertical li.current>a {
  color: rgba(0, 93, 255, 0.9);
  font-weight: 700;
  position: relative;
  background: #fafafa;
  border: none;
}

/*.wy-menu-vertical li.on a:hover span.toctree-expand,
.wy-menu-vertical li.current>a:hover span.toctree-expand {
  color: gray;
}*/

.wy-menu-vertical li.on a span.toctree-expand,
.wy-menu-vertical li.current>a span.toctree-expand {
  display: block;
  font-size: .8em;
  line-height: 1.6em;
  color: #333;
}

.wy-menu-vertical li.toctree-l1.current li.toctree-l2>ul,
.wy-menu-vertical li.toctree-l2.current li.toctree-l3>ul {
  display: none;
}

.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current>ul,
.wy-menu-vertical li.toctree-l2.current li.toctree-l3.current>ul {
  display: block;
}

.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a {
  display: block;
  padding: .4045em 4.045em;
}

.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
  color: #999;
}

.wy-menu-vertical li.toctree-l2 span.toctree-expand {
  color: #999;
}

.wy-menu-vertical li.toctree-l3 {
  background-color: #eee;
  font-size: .9em;
}

.wy-menu-vertical li.toctree-l3.current>a {
  padding: .4045em 4.045em;
}

.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a {
  display: block;
  padding: .4045em 5.663em;
  border-top: none;
  border-bottom: none;
}

.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand {
  color: rgba(0, 93, 255, 0.9);
}

.wy-menu-vertical li.toctree-l3 span.toctree-expand {
  color: #999;
}

.wy-menu-vertical li.toctree-l4 {
  font-size: .9em;
}

.wy-menu-vertical li.current ul {
  display: block;
}

.wy-menu-vertical .local-toc li ul {
  display: block;
}

.wy-menu-vertical li ul li a {
  margin-bottom: 0;
  color: rgba(0, 93, 255, 0.7);
  font-weight: 400;
}

.wy-menu-vertical a {
  display: inline-block;
  line-height: 18px;
  padding: .4045em 1.618em;
  display: block;
  position: relative;
  font-size: 90%;
  color: rgba(0, 93, 255, 0.7);
}

.wy-menu-vertical li.on a:hover,
.wy-menu-vertical li.current>a:hover {
  background-color: #fafafa;
}

.wy-menu-vertical a:hover {
  color: rgba(0, 93, 255, 0.9);
  cursor: pointer;
  background-color: #fafafa;
}

.wy-menu-vertical a:hover span.toctree-expand {
  color: rgba(0, 93, 255, 0.5);
}

.wy-menu-vertical a:active span.toctree-expand {
  color: rgba(0, 93, 255, 0.7);
}

/* Search */

.wy-side-nav-search {
  z-index: 200;
  background-color: #fafafa;
  border-bottom: #333;
  text-align: center;
  padding: .809em;
  display: block;
  color: #333;
  margin-bottom: .809em
}

.wy-side-nav-search input[type=text] {
  width: 100%;
  color: #333;
  border-radius: 3px;
  outline: 0;
  padding: 10px;
  background-color: #fff;
  border: solid 1px #6d6d6d;
  box-shadow: none
}

.wy-side-nav-search img {
  display: block;
  margin: auto auto .809em;
  height: 45px;
  width: 45px;
  background-color: #2980B9;
  padding: 5px;
  border-radius: 100%
}

.wy-side-nav-search>a,
.wy-side-nav-search .wy-dropdown>a {
  color: #333;
  font-size: 100%;
  font-weight: 700;
  display: inline-block;
  padding: 4px 6px;
  margin-bottom: .809em
}

.wy-side-nav-search>a:hover,
.wy-side-nav-search .wy-dropdown>a:hover {
  background: rgba(255,255,255,0.1)
}

.wy-side-nav-search>a img.logo,
.wy-side-nav-search .wy-dropdown>a img.logo {
  display: block;
  margin: 0 auto;
  height: auto;
  width: auto;
  border-radius: 0;
  max-width: 100%;
  background: transparent
}

.wy-side-nav-search>a.icon img.logo,
.wy-side-nav-search .wy-dropdown>a.icon img.logo {
  margin-top: .85em
}

.wy-nav .wy-menu-vertical header {
  color: #2980B9
}

.wy-nav .wy-menu-vertical a {
  color: #b3b3b3
}

.wy-nav .wy-menu-vertical a:hover {
  background-color: #2980B9;
  color: #fff
}

[data-menu-wrap] {
  -webkit-transition: all .2s ease-in;
  -moz-transition: all .2s ease-in;
  transition: all .2s ease-in;
  position: absolute;
  opacity: 1;
  width: 100%;
  opacity: 0
}

[data-menu-wrap].move-center {
  left: 0;
  right: auto;
  opacity: 1
}

[data-menu-wrap].move-left {
  right: auto;
  left: -100%;
  opacity: 0
}

[data-menu-wrap].move-right {
  right: -100%;
  left: auto;
  opacity: 0
}

.wy-body-for-nav {
  background: left repeat-y #fcfcfc;
  background-image: url(data:image/png;
  base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxOERBMTRGRDBFMUUxMUUzODUwMkJCOThDMEVFNURFMCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxOERBMTRGRTBFMUUxMUUzODUwMkJCOThDMEVFNURFMCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjE4REExNEZCMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjE4REExNEZDMEUxRTExRTM4NTAyQkI5OEMwRUU1REUwIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+EwrlwAAAAA5JREFUeNpiMDU0BAgwAAE2AJgB9BnaAAAAAElFTkSuQmCC);
  background-size: 300px 1px
}

.wy-grid-for-nav {
  position: absolute;
  width: 100%;
  height: 100%
}

.wy-nav-side {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  padding-bottom: 2em;
  width: 300px;
  overflow-x: hidden;
  overflow-y: scroll;
  min-height: 100%;
  background-color: #fafafa;
  z-index: 200;
  border-right: 2px solid #eee;
}

.wy-nav-top {
  display: none;
  background-color: #333;
  color: #fff;
  padding: .4045em .809em;
  position: relative;
  line-height: 50px;
  text-align: center;
  font-size: 100%;
  *zoom: 1
}

.wy-nav-top:before,
.wy-nav-top:after {
  display: table;
  content: ""
}

.wy-nav-top:after {
  clear: both
}

.wy-nav-top a {
  color: #fff;
  font-weight: 700
}

.wy-nav-top img {
  margin-right: 12px;
  height: 45px;
  width: 45px;
  background-color: #2980B9;
  padding: 5px;
  border-radius: 100%
}

.wy-nav-top i {
  font-size: 30px;
  line-height: 50px;
  float: left;
  cursor: pointer
}

.wy-nav-content-wrap {
  margin-left: 300px;
  background: #fcfcfc;
  min-height: 100%
}

.wy-nav-content {
  padding: 1.618em 3.236em;
  height: 100%;
  max-width: 1100px;
  margin: auto
}

.wy-body-mask {
  position: fixed;
  width: 100%;
  height: 100%;
  background: rgba(0,0,0,0.2);
  display: none;
  z-index: 499
}

.wy-body-mask.on {
  display: block
}

@media screen and (max-width: 768px) {
  .wy-body-for-nav {
    background: #fcfcfc
  }

  .wy-nav-top {
    display: block
  }

  .wy-nav-side {
    left: -300px
  }

  .wy-nav-side.shift {
    width: 85%;
    left: 0
  }

  .wy-nav-content-wrap {
    margin-left: 0
  }

  .wy-nav-content-wrap .wy-nav-content {
    padding: 1.618em
  }

  .wy-nav-content-wrap.shift {
    position: fixed;
    min-width: 100%;
    left: 85%;
    top: 0;
    height: 100%;
    overflow: hidden
  }

}

@media screen and (min-width: 1400px) {
  .wy-nav-content {
    margin: 0;
    background: #fcfcfc
  }
}

================================================
FILE: docs/getting-started/basics.md
================================================
### Overview
Gor architecture tries to follow UNIX philosophy: everything made of pipes, various inputs multiplexing data to outputs.

You can [rate limit](/rate-limiting.md), [filter](request-filtering.md), [rewrite](request-rewriting.md) requests or even use your own [middleware](middleware.md) to implement custom logic. Also, it is possible to replay requests at the higher rate for [load testing](saving-and-replaying-from-file.md).

### Available inputs

* `--input-raw` - used to capture HTTP traffic, you should specify IP address or interface and application port. More about [[Capturing and replaying traffic]]. 
* `--input-file` - accepts file which previously was recorded using ` --output-file`. More about [[Saving and Replaying from file]]
* `--input-tcp` - used by Gor aggregation instance if you decided forward traffic from multiple forwarder Gor instances to it. Read about using [[Aggregator-forwarder setup]].

### Available outputs

* `--output-http` - replay HTTP traffic to given endpoint, accepts base url. Read [more about it](Replaying HTTP traffic)
* `--output-file` - records incoming traffic to the file. More about [[Saving and Replaying from file]]
* `--output-tcp` - forward incoming data to another Gor instance, used in conjunction with `--input-tcp`. Read more about [[Aggregator-forwarder setup]].
* `--output-stdout` - used for debugging, outputs all data to stdout.

================================================
FILE: docs/getting-started/tutorial.md
================================================
### Dependencies
To start working with Gor, you need to have a web server running on your machine, and a terminal to run commands. If you are just poking around, you can quickly start the server by calling `gor file-server :8000`, this will start a simple file server of the current directory on port `8000`. 

### Installing Gor
Download the latest Gor binary from https://github.com/buger/gor/releases (we provide precompiled binaries for Windows, Linux x64 and Mac OS), or you can compile by yourself [[Compilation]].

Once the archive is downloaded and uncompressed, you can run Gor from the current directory, or you may want to copy binary to your PATH (for Linux and Mac OS it can be `/usr/local/bin`).

### Capturing web traffic
Now run this command in terminal: `sudo ./gor --input-raw :8000 --output-stdout`

This command says to listen for all network activity happening on port 8000 and log it to stdout.
If you are familiar with `tcpdump`, we are going to implement similar functionality. 

> You may notice that it uses `sudo` and asks for the password: to analyze network, Gor needs permissions which are available only to super users.
> However, it is possible to configure Gor [being run for non-root users](Running-as-non-root-user).


Make a few requests by opening `http://localhost:8000` in your browser, or just by calling curl in terminal `curl http://localhost:8000`. You should see that `gor` outputs all the HTTP requests and responses right to the terminal window where it is running. 


**Gor is not a proxy:** you do not need to put 3-rd party tool to your critical path. Instead Gor just silently analyzes the traffic of your application and does not affect it anyhow.

### Replaying

Now it's time to replay your original traffic to another environment. Let's start the same file web server but on a different port: `gor file-server :8001`. 

Instead of `--output-stdout` we will use `--output-http` and provide URL of second server: `sudo ./gor --input-raw :8000 --output-http="http://localhost:8001"`

Make few requests to first server. You should see them replicated to the second one, voila! 

### Saving requests to file and replaying them later
Sometimes it's not possible to replay requests in real time; Gor allows you to save requests to the file and replay them later. 

First use `--output-file` to save them: `sudo ./gor --input-raw :8000 --output-file=requests.gor`. This will create new file and continuously write all captured requests to it. 

Let's re-run Gor, but now to replay requests from file: `./gor --input-file requests.gor --output-http="http://localhost:8001"`. You should see all the recorded requests coming to the second server, and they will be replayed in the same order and with exactly same timing as they were recorded.

Next: [[The Basics]]

### Watch an overview:


![YOUTUBE](https://www.youtube.com/watch?v=CxuKZcMKaW4)

================================================
FILE: docs/index.md
================================================
Gor is an open-source tool for capturing and replaying live HTTP traffic into a test environment in order to continuously test your system with real data. It can be used to increase confidence in code deployments, configuration changes and infrastructure changes.

Read for more info:

* [[Getting Started]]
* [[The Basics]]
* [[Capturing and replaying traffic]]
* [[Replaying HTTP traffic]]
* [[[PRO] Replaying Binary protocols]]
* [[[PRO] Recording and replaying keep alive TCP sessions]]
* [[Saving and Replaying from file]]
* [Performance testing](https://github.com/buger/gor/wiki/Saving-and-Replaying-from-file#performance-testing)
* [[Rate limiting]]
* [[Request filtering]]
* [[Request rewriting]]
* [[Middleware]]
* [[Distributed configuration]]
* [[Exporting to ElasticSearch]]
* [[FAQ]]
* [[Troubleshooting]]

## Commercial Aspects

* [[Commercial Support]]
* [[Commercial FAQ]]
* [[Commercial collaboration]]


Next: [Getting Started](Getting-Started)


================================================
FILE: docs/js/base.js
================================================
$(document).ready(function () {
    $('img[alt="YOUTUBE"]').each(function () {
        var id = $(this).attr('src').split('/')[$(this).attr('src').split('/').length - 1].split("=")[1];
        var video = '<iframe style="width: 100%;height: 450px;" src="https://www.youtube.com/embed/' + id + '" frameborder="0" allowfullscreen></iframe>';
        $(this).replaceWith(video);
    });
});

================================================
FILE: docs/js/turbolinks.js
================================================
/*
Turbolinks 5.0.0
Copyright © 2016 Basecamp, LLC
 */
(function(){(function(){(function(){this.Turbolinks={supported:function(){return null!=window.history.pushState&&null!=window.requestAnimationFrame}(),visit:function(e,r){return t.controller.visit(e,r)},clearCache:function(){return t.controller.clearCache()}}}).call(this)}).call(this);var t=this.Turbolinks;(function(){(function(){var e,r;t.copyObject=function(t){var e,r,n;r={};for(e in t)n=t[e],r[e]=n;return r},t.closest=function(t,r){return e.call(t,r)},e=function(){var t,e;return t=document.documentElement,null!=(e=t.closest)?e:function(t){var e;for(e=this;e;){if(e.nodeType===Node.ELEMENT_NODE&&r.call(e,t))return e;e=e.parentNode}}}(),t.defer=function(t){return setTimeout(t,1)},t.dispatch=function(t,e){var r,n,o,i,s;return i=null!=e?e:{},s=i.target,r=i.cancelable,n=i.data,o=document.createEvent("Events"),o.initEvent(t,!0,r===!0),o.data=null!=n?n:{},(null!=s?s:document).dispatchEvent(o),o},t.match=function(t,e){return r.call(t,e)},r=function(){var t,e,r,n;return t=document.documentElement,null!=(e=null!=(r=null!=(n=t.matchesSelector)?n:t.webkitMatchesSelector)?r:t.msMatchesSelector)?e:t.mozMatchesSelector}(),t.uuid=function(){var t,e,r;for(r="",t=e=1;36>=e;t=++e)r+=9===t||14===t||19===t||24===t?"-":15===t?"4":20===t?(Math.floor(4*Math.random())+8).toString(16):Math.floor(15*Math.random()).toString(16);return r}}).call(this),function(){t.Location=function(){function t(t){var e,r;null==t&&(t=""),r=document.createElement("a"),r.href=t.toString(),this.absoluteURL=r.href,e=r.hash.length,2>e?this.requestURL=this.absoluteURL:(this.requestURL=this.absoluteURL.slice(0,-e),this.anchor=r.hash.slice(1))}var e,r,n,o;return t.wrap=function(t){return t instanceof this?t:new this(t)},t.prototype.getOrigin=function(){return this.absoluteURL.split("/",3).join("/")},t.prototype.getPath=function(){var t,e;return null!=(t=null!=(e=this.absoluteURL.match(/\/\/[^\/]*(\/[^?;]*)/))?e[1]:void 0)?t:"/"},t.prototype.getPathComponents=function(){return this.getPath().split("/").slice(1)},t.prototype.getLastPathComponent=function(){return this.getPathComponents().slice(-1)[0]},t.prototype.getExtension=function(){var t,e;return null!=(t=null!=(e=this.getLastPathComponent().match(/\.[^.]*$/))?e[0]:void 0)?t:""},t.prototype.isHTML=function(){return this.getExtension().match(/^(?:|\.(?:htm|html|xhtml))$/)},t.prototype.isPrefixedBy=function(t){var e;return e=r(t),this.isEqualTo(t)||o(this.absoluteURL,e)},t.prototype.isEqualTo=function(t){return this.absoluteURL===(null!=t?t.absoluteURL:void 0)},t.prototype.toCacheKey=function(){return this.requestURL},t.prototype.toJSON=function(){return this.absoluteURL},t.prototype.toString=function(){return this.absoluteURL},t.prototype.valueOf=function(){return this.absoluteURL},r=function(t){return e(t.getOrigin()+t.getPath())},e=function(t){return n(t,"/")?t:t+"/"},o=function(t,e){return t.slice(0,e.length)===e},n=function(t,e){return t.slice(-e.length)===e},t}()}.call(this),function(){var e=function(t,e){return function(){return t.apply(e,arguments)}};t.HttpRequest=function(){function r(r,n,o){this.delegate=r,this.requestCanceled=e(this.requestCanceled,this),this.requestTimedOut=e(this.requestTimedOut,this),this.requestFailed=e(this.requestFailed,this),this.requestLoaded=e(this.requestLoaded,this),this.requestProgressed=e(this.requestProgressed,this),this.url=t.Location.wrap(n).requestURL,this.referrer=t.Location.wrap(o).absoluteURL,this.createXHR()}return r.NETWORK_FAILURE=0,r.TIMEOUT_FAILURE=-1,r.timeout=60,r.prototype.send=function(){var t;return this.xhr&&!this.sent?(this.notifyApplicationBeforeRequestStart(),this.setProgress(0),this.xhr.send(),this.sent=!0,"function"==typeof(t=this.delegate).requestStarted?t.requestStarted():void 0):void 0},r.prototype.cancel=function(){return this.xhr&&this.sent?this.xhr.abort():void 0},r.prototype.requestProgressed=function(t){return t.lengthComputable?this.setProgress(t.loaded/t.total):void 0},r.prototype.requestLoaded=function(){return this.endRequest(function(t){return function(){var e;return 200<=(e=t.xhr.status)&&300>e?t.delegate.requestCompletedWithResponse(t.xhr.responseText,t.xhr.getResponseHeader("Turbolinks-Location")):(t.failed=!0,t.delegate.requestFailedWithStatusCode(t.xhr.status,t.xhr.responseText))}}(this))},r.prototype.requestFailed=function(){return this.endRequest(function(t){return function(){return t.failed=!0,t.delegate.requestFailedWithStatusCode(t.constructor.NETWORK_FAILURE)}}(this))},r.prototype.requestTimedOut=function(){return this.endRequest(function(t){return function(){return t.failed=!0,t.delegate.requestFailedWithStatusCode(t.constructor.TIMEOUT_FAILURE)}}(this))},r.prototype.requestCanceled=function(){return this.endRequest()},r.prototype.notifyApplicationBeforeRequestStart=function(){return t.dispatch("turbolinks:request-start",{data:{url:this.url,xhr:this.xhr}})},r.prototype.notifyApplicationAfterRequestEnd=function(){return t.dispatch("turbolinks:request-end",{data:{url:this.url,xhr:this.xhr}})},r.prototype.createXHR=function(){return this.xhr=new XMLHttpRequest,this.xhr.open("GET",this.url,!0),this.xhr.timeout=1e3*this.constructor.timeout,this.xhr.setRequestHeader("Accept","text/html, application/xhtml+xml"),this.xhr.setRequestHeader("Turbolinks-Referrer",this.referrer),this.xhr.onprogress=this.requestProgressed,this.xhr.onload=this.requestLoaded,this.xhr.onerror=this.requestFailed,this.xhr.ontimeout=this.requestTimedOut,this.xhr.onabort=this.requestCanceled},r.prototype.endRequest=function(t){return this.xhr?(this.notifyApplicationAfterRequestEnd(),null!=t&&t.call(this),this.destroy()):void 0},r.prototype.setProgress=function(t){var e;return this.progress=t,"function"==typeof(e=this.delegate).requestProgressed?e.requestProgressed(this.progress):void 0},r.prototype.destroy=function(){var t;return this.setProgress(1),"function"==typeof(t=this.delegate).requestFinished&&t.requestFinished(),this.delegate=null,this.xhr=null},r}()}.call(this),function(){var e=function(t,e){return function(){return t.apply(e,arguments)}};t.ProgressBar=function(){function t(){this.trickle=e(this.trickle,this),this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement()}var r;return r=300,t.defaultCSS=".turbolinks-progress-bar {\n  position: fixed;\n  display: block;\n  top: 0;\n  left: 0;\n  height: 3px;\n  background: #0076ff;\n  z-index: 9999;\n  transition: width "+r+"ms ease-out, opacity "+r/2+"ms "+r/2+"ms ease-in;\n  transform: translate3d(0, 0, 0);\n}",t.prototype.show=function(){return this.visible?void 0:(this.visible=!0,this.installStylesheetElement(),this.installProgressElement(),this.startTrickling())},t.prototype.hide=function(){return this.visible&&!this.hiding?(this.hiding=!0,this.fadeProgressElement(function(t){return function(){return t.uninstallProgressElement(),t.stopTrickling(),t.visible=!1,t.hiding=!1}}(this))):void 0},t.prototype.setValue=function(t){return this.value=t,this.refresh()},t.prototype.installStylesheetElement=function(){return document.head.insertBefore(this.stylesheetElement,document.head.firstChild)},t.prototype.installProgressElement=function(){return this.progressElement.style.width=0,this.progressElement.style.opacity=1,document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()},t.prototype.fadeProgressElement=function(t){return this.progressElement.style.opacity=0,setTimeout(t,1.5*r)},t.prototype.uninstallProgressElement=function(){return this.progressElement.parentNode?document.documentElement.removeChild(this.progressElement):void 0},t.prototype.startTrickling=function(){return null!=this.trickleInterval?this.trickleInterval:this.trickleInterval=setInterval(this.trickle,r)},t.prototype.stopTrickling=function(){return clearInterval(this.trickleInterval),this.trickleInterval=null},t.prototype.trickle=function(){return this.setValue(this.value+Math.random()/100)},t.prototype.refresh=function(){return requestAnimationFrame(function(t){return function(){return t.progressElement.style.width=10+90*t.value+"%"}}(this))},t.prototype.createStylesheetElement=function(){var t;return t=document.createElement("style"),t.type="text/css",t.textContent=this.constructor.defaultCSS,t},t.prototype.createProgressElement=function(){var t;return t=document.createElement("div"),t.className="turbolinks-progress-bar",t},t}()}.call(this),function(){var e=function(t,e){return function(){return t.apply(e,arguments)}};t.BrowserAdapter=function(){function r(r){this.controller=r,this.showProgressBar=e(this.showProgressBar,this),this.progressBar=new t.ProgressBar}var n,o,i,s;return s=t.HttpRequest,n=s.NETWORK_FAILURE,i=s.TIMEOUT_FAILURE,o=500,r.prototype.visitProposedToLocationWithAction=function(t,e){return this.controller.startVisitToLocationWithAction(t,e)},r.prototype.visitStarted=function(t){return t.issueRequest(),t.changeHistory(),t.loadCachedSnapshot()},r.prototype.visitRequestStarted=function(t){return this.progressBar.setValue(0),t.hasCachedSnapshot()||"restore"!==t.action?this.showProgressBarAfterDelay():this.showProgressBar()},r.prototype.visitRequestProgressed=function(t){return this.progressBar.setValue(t.progress)},r.prototype.visitRequestCompleted=function(t){return t.loadResponse()},r.prototype.visitRequestFailedWithStatusCode=function(t,e){switch(e){case n:case i:return this.reload();default:return t.loadResponse()}},r.prototype.visitRequestFinished=function(t){return this.hideProgressBar()},r.prototype.visitCompleted=function(t){return t.followRedirect()},r.prototype.pageInvalidated=function(){return this.reload()},r.prototype.showProgressBarAfterDelay=function(){return this.progressBarTimeout=setTimeout(this.showProgressBar,o)},r.prototype.showProgressBar=function(){return this.progressBar.show()},r.prototype.hideProgressBar=function(){return this.progressBar.hide(),clearTimeout(this.progressBarTimeout)},r.prototype.reload=function(){return window.location.reload()},r}()}.call(this),function(){var e,r=function(t,e){return function(){return t.apply(e,arguments)}};e=!1,addEventListener("load",function(){return t.defer(function(){return e=!0})},!1),t.History=function(){function n(t){this.delegate=t,this.onPopState=r(this.onPopState,this)}return n.prototype.start=function(){return this.started?void 0:(addEventListener("popstate",this.onPopState,!1),this.started=!0)},n.prototype.stop=function(){return this.started?(removeEventListener("popstate",this.onPopState,!1),this.started=!1):void 0},n.prototype.push=function(e,r){return e=t.Location.wrap(e),this.update("push",e,r)},n.prototype.replace=function(e,r){return e=t.Location.wrap(e),this.update("replace",e,r)},n.prototype.onPopState=function(e){var r,n,o,i;return this.shouldHandlePopState()&&(i=null!=(n=e.state)?n.turbolinks:void 0)?(r=t.Location.wrap(window.location),o=i.restorationIdentifier,this.delegate.historyPoppedToLocationWithRestorationIdentifier(r,o)):void 0},n.prototype.shouldHandlePopState=function(){return e===!0},n.prototype.update=function(t,e,r){var n;return n={turbolinks:{restorationIdentifier:r}},history[t+"State"](n,null,e)},n}()}.call(this),function(){t.Snapshot=function(){function e(t){var e,r;r=t.head,e=t.body,this.head=null!=r?r:document.createElement("head"),this.body=null!=e?e:document.createElement("body")}return e.wrap=function(t){return t instanceof this?t:this.fromHTML(t)},e.fromHTML=function(t){var e;return e=document.createElement("html"),e.innerHTML=t,this.fromElement(e)},e.fromElement=function(t){return new this({head:t.querySelector("head"),body:t.querySelector("body")})},e.prototype.clone=function(){return new e({head:this.head.cloneNode(!0),body:this.body.cloneNode(!0)})},e.prototype.getRootLocation=function(){var e,r;return r=null!=(e=this.getSetting("root"))?e:"/",new t.Location(r)},e.prototype.getCacheControlValue=function(){return this.getSetting("cache-control")},e.prototype.hasAnchor=function(t){try{return null!=this.body.querySelector("[id='"+t+"']")}catch(e){}},e.prototype.isPreviewable=function(){return"no-preview"!==this.getCacheControlValue()},e.prototype.isCacheable=function(){return"no-cache"!==this.getCacheControlValue()},e.prototype.getSettin
Download .txt
gitextract_1d_7z0pv/

├── .clabot
├── .deepsource.toml
├── .dockerignore
├── .github/
│   ├── dependabot.yaml
│   └── workflows/
│       ├── ci-docker.yaml
│       ├── ci-test.yaml
│       ├── codesee-arch-diagram.yml
│       ├── probe.yaml
│       └── semgrep.yml
├── .gitignore
├── .gitmodules
├── .request
├── COMM-LICENSE
├── Dockerfile
├── Dockerfile.dev
├── ELASTICSEARCH.md
├── LICENSE.txt
├── Makefile
├── Procfile
├── README.md
├── ce.go
├── circle.yml
├── docs/
│   ├── CNAME
│   ├── Capturing-and-replaying-traffic.md
│   ├── Compilation.md
│   ├── Development-Setup.md
│   ├── Distributed-configuration.md
│   ├── Exporting-to-ElasticSearch.md
│   ├── FAQ.md
│   ├── Middleware.md
│   ├── Rate-limiting.md
│   ├── Replaying-HTTP-traffic.md
│   ├── Request-filtering.md
│   ├── Request-rewriting.md
│   ├── Running-as-non-root-user.md
│   ├── Saving-and-Replaying-from-file.md
│   ├── Troubleshooting.md
│   ├── _Footer.md
│   ├── _config.yml
│   ├── commercial/
│   │   ├── collaboration.md
│   │   ├── faq.md
│   │   └── support.md
│   ├── css/
│   │   ├── breadcrumbs.css
│   │   ├── code.css
│   │   ├── fabric.css
│   │   ├── goreplay.css
│   │   └── sidenav.css
│   ├── getting-started/
│   │   ├── basics.md
│   │   └── tutorial.md
│   ├── index.md
│   ├── js/
│   │   ├── base.js
│   │   └── turbolinks.js
│   └── pro/
│       ├── recording-and-replaying-keep-alive-tcp-sessions.md
│       └── replaying-binary-protocols.md
├── elasticsearch.go
├── elasticsearch_test.go
├── emitter.go
├── emitter_test.go
├── examples/
│   └── middleware/
│       ├── echo.clj
│       ├── echo.java
│       ├── echo.js
│       ├── echo.py
│       ├── echo.rb
│       ├── echo.sh
│       └── token_modifier.go
├── go.mod
├── go.sum
├── gor_stat.go
├── homebrew/
│   └── gor.rb
├── http_modifier.go
├── http_modifier_settings.go
├── http_modifier_settings_test.go
├── http_modifier_test.go
├── http_prettifier.go
├── http_prettifier_test.go
├── input_dummy.go
├── input_file.go
├── input_file_test.go
├── input_http.go
├── input_http_test.go
├── input_kafka.go
├── input_kafka_test.go
├── input_raw.go
├── input_raw_test.go
├── input_tcp.go
├── input_tcp_test.go
├── internal/
│   ├── byteutils/
│   │   ├── byteutils.go
│   │   └── byteutils_test.go
│   ├── capture/
│   │   ├── af_packet.go
│   │   ├── af_packet_linux.go
│   │   ├── capture.go
│   │   ├── capture_test.go
│   │   ├── doc.go
│   │   ├── dump.go
│   │   ├── sock_linux.go
│   │   ├── sock_others.go
│   │   ├── socket.go
│   │   └── vxlan.go
│   ├── ring/
│   │   └── ring.go
│   ├── simpletime/
│   │   └── time.go
│   ├── size/
│   │   ├── size.go
│   │   └── size_test.go
│   └── tcp/
│       ├── doc.go
│       ├── tcp_message.go
│       ├── tcp_packet.go
│       └── tcp_test.go
├── k8s/
│   ├── README.md
│   ├── clusterrole.yaml
│   ├── collect_goreplay_telemetry.sh
│   ├── goreplay.yaml
│   ├── nginx.yaml
│   └── rolebinding.yaml
├── kafka.go
├── limiter.go
├── limiter_test.go
├── middleware/
│   ├── README.md
│   ├── middleware.js
│   └── package.json
├── middleware.go
├── middleware_test.go
├── mkdocs.yml
├── nfpm.yaml
├── output_binary.go
├── output_binary_pro.go
├── output_dummy.go
├── output_file.go
├── output_file_test.go
├── output_http.go
├── output_http_test.go
├── output_kafka.go
├── output_kafka_test.go
├── output_null.go
├── output_s3.go
├── output_s3_pro.go
├── output_tcp.go
├── output_tcp_test.go
├── output_ws.go
├── output_ws_test.go
├── plugins.go
├── plugins_test.go
├── pro.go
├── proto/
│   ├── fuzz.go
│   ├── proto.go
│   └── proto_test.go
├── protocol.go
├── s3/
│   └── index.html
├── s3_reader.go
├── s3_test.go
├── settings.go
├── settings_test.go
├── sidenav.css
├── site/
│   ├── .gitignore
│   ├── Gemfile
│   ├── _config.yml
│   ├── _posts/
│   │   └── 2017-01-06-welcome-to-jekyll.markdown
│   ├── about.md
│   └── index.md
├── snapcraft.yaml
├── tcp_client.go
├── test_input.go
├── test_output.go
└── version.go
Download .txt
SYMBOL INDEX (748 symbols across 82 files)

FILE: ce.go
  function SettingsHook (line 12) | func SettingsHook(settings *AppSettings) {

FILE: docs/js/turbolinks.js
  function t (line 5) | function t(t){var e,r;null==t&&(t=""),r=document.createElement("a"),r.hr...
  function r (line 5) | function r(r,n,o){this.delegate=r,this.requestCanceled=e(this.requestCan...
  function t (line 5) | function t(){this.trickle=e(this.trickle,this),this.stylesheetElement=th...
  function r (line 5) | function r(r){this.controller=r,this.showProgressBar=e(this.showProgress...
  function n (line 5) | function n(t){this.delegate=t,this.onPopState=r(this.onPopState,this)}
  function e (line 5) | function e(t){var e,r;r=t.head,e=t.body,this.head=null!=r?r:document.cre...
  function t (line 5) | function t(){}
  function t (line 5) | function t(t){var e,r,i,s,a,u,c;for(this.element=t,this.elements={},c=th...
  function n (line 5) | function n(){this.constructor=t}
  function n (line 5) | function n(e,r){this.currentSnapshot=e,this.newSnapshot=r,this.currentHe...
  function n (line 5) | function n(){this.constructor=t}
  function r (line 5) | function r(t){this.html=t}
  function e (line 5) | function e(t){this.delegate=t,this.element=document.documentElement}
  function t (line 5) | function t(t){this.delegate=t,this.onScroll=e(this.onScroll,this)}
  function e (line 5) | function e(t){this.size=t,this.keys=[],this.snapshots={}}
  function r (line 5) | function r(r,n,o){this.controller=r,this.action=o,this.performScroll=e(t...
  function r (line 5) | function r(){this.clickBubbled=e(this.clickBubbled,this),this.clickCaptu...

FILE: elasticsearch.go
  type ESUriErorr (line 14) | type ESUriErorr struct
    method Error (line 16) | func (e *ESUriErorr) Error() string {
  type ESPlugin (line 20) | type ESPlugin struct
    method Init (line 84) | func (p *ESPlugin) Init(URI string) {
    method IndexerShutdown (line 107) | func (p *ESPlugin) IndexerShutdown() {
    method ErrorHandler (line 112) | func (p *ESPlugin) ErrorHandler() {
    method RttDurationToMs (line 119) | func (p *ESPlugin) RttDurationToMs(d time.Duration) int64 {
    method ResponseAnalyze (line 127) | func (p *ESPlugin) ResponseAnalyze(req, resp []byte, start, stop time....
  type ESRequestResponse (line 30) | type ESRequestResponse struct
  function parseURI (line 62) | func parseURI(URI string) (err error, index string) {

FILE: elasticsearch_test.go
  constant expectedIndex (line 7) | expectedIndex = "gor"
  function assertExpectedGorIndex (line 9) | func assertExpectedGorIndex(index string, t *testing.T) {
  function assertExpectedIndex (line 15) | func assertExpectedIndex(expectedIndex string, index string, t *testing....
  function assertExpectedError (line 21) | func assertExpectedError(returnedError error, t *testing.T) {
  function assertNoError (line 29) | func assertNoError(returnedError error, t *testing.T) {
  function TestElasticConnectionBuildFailWithoutScheme (line 38) | func TestElasticConnectionBuildFailWithoutScheme(t *testing.T) {
  function TestElasticConnectionBuildFailWithoutIndex (line 48) | func TestElasticConnectionBuildFailWithoutIndex(t *testing.T) {
  function TestElasticConnectionBuildFailWithoutPort (line 60) | func TestElasticConnectionBuildFailWithoutPort(t *testing.T) {
  function TestElasticLocalConnectionBuild (line 72) | func TestElasticLocalConnectionBuild(t *testing.T) {
  function TestElasticSimpleLocalWithSchemeConnectionBuild (line 84) | func TestElasticSimpleLocalWithSchemeConnectionBuild(t *testing.T) {
  function TestElasticSimpleLocalWithHTTPSConnectionBuild (line 96) | func TestElasticSimpleLocalWithHTTPSConnectionBuild(t *testing.T) {
  function TestElasticLongPathConnectionBuild (line 108) | func TestElasticLongPathConnectionBuild(t *testing.T) {
  function TestElasticBasicAuthConnectionBuild (line 120) | func TestElasticBasicAuthConnectionBuild(t *testing.T) {
  function TestElasticComplexPathConnectionBuild (line 132) | func TestElasticComplexPathConnectionBuild(t *testing.T) {

FILE: emitter.go
  type Emitter (line 15) | type Emitter struct
    method Start (line 26) | func (e *Emitter) Start(plugins *InOutPlugins, middlewareCmd string) {
    method Close (line 62) | func (e *Emitter) Close() {
  function NewEmitter (line 21) | func NewEmitter() *Emitter {
  function CopyMulty (line 76) | func CopyMulty(src PluginReader, writers ...PluginWriter) error {

FILE: emitter_test.go
  function TestMain (line 12) | func TestMain(m *testing.M) {
  function TestEmitter (line 18) | func TestEmitter(t *testing.T) {
  function TestEmitterFiltered (line 44) | func TestEmitterFiltered(t *testing.T) {
  function TestEmitterSplitRoundRobin (line 94) | func TestEmitterSplitRoundRobin(t *testing.T) {
  function TestEmitterRoundRobin (line 137) | func TestEmitterRoundRobin(t *testing.T) {
  function TestEmitterSplitSession (line 180) | func TestEmitterSplitSession(t *testing.T) {
  function BenchmarkEmitter (line 236) | func BenchmarkEmitter(b *testing.B) {

FILE: examples/middleware/echo.java
  class Echo (line 9) | class Echo {
    method decodeHexString (line 10) | public static String decodeHexString(String s) throws DecoderException {
    method encodeHexString (line 14) | public static String encodeHexString(String s) {
    method transformHTTPMessage (line 18) | public static String transformHTTPMessage(String req) {
    method main (line 23) | public static void main(String[] args) throws DecoderException {

FILE: examples/middleware/echo.js
  function convertHexString (line 13) | function convertHexString(hex) {
  function log (line 21) | function log(output) {
  function shouldOutputLine (line 26) | function shouldOutputLine(request) {

FILE: examples/middleware/echo.py
  function log (line 12) | def log(msg):
  function find_end_of_headers (line 26) | def find_end_of_headers(byte_data):
  function process_stdin (line 35) | def process_stdin():

FILE: examples/middleware/token_modifier.go
  function main (line 37) | func main() {
  function process (line 52) | func process(buf []byte) {
  function encode (line 108) | func encode(buf []byte) []byte {
  function Debug (line 116) | func Debug(args ...interface{}) {

FILE: gor_stat.go
  type GorStat (line 9) | type GorStat struct
    method Write (line 33) | func (s *GorStat) Write(latest int) {
    method Reset (line 46) | func (s *GorStat) Reset() {
    method String (line 53) | func (s *GorStat) String() string {
    method reportStats (line 57) | func (s *GorStat) reportStats() {
  function NewGorStat (line 18) | func NewGorStat(statName string, rateMs int) (s *GorStat) {

FILE: homebrew/gor.rb
  class Gor (line 3) | class Gor < Formula
    method install (line 34) | def install

FILE: http_modifier.go
  type HTTPModifier (line 11) | type HTTPModifier struct
    method Rewrite (line 35) | func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) {
  function NewHTTPModifier (line 15) | func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier {

FILE: http_modifier_settings.go
  type HTTPModifierConfig (line 12) | type HTTPModifierConfig struct
  type headerFilter (line 28) | type headerFilter struct
  type HTTPHeaderFilters (line 34) | type HTTPHeaderFilters
    method String (line 36) | func (h *HTTPHeaderFilters) String() string {
    method Set (line 41) | func (h *HTTPHeaderFilters) Set(value string) error {
  type basicAuthFilter (line 58) | type basicAuthFilter struct
  type HTTPHeaderBasicAuthFilters (line 63) | type HTTPHeaderBasicAuthFilters
    method String (line 65) | func (h *HTTPHeaderBasicAuthFilters) String() string {
    method Set (line 70) | func (h *HTTPHeaderBasicAuthFilters) Set(value string) error {
  type hashFilter (line 82) | type hashFilter struct
  type HTTPHashFilters (line 88) | type HTTPHashFilters
    method String (line 90) | func (h *HTTPHashFilters) String() string {
    method Set (line 95) | func (h *HTTPHashFilters) Set(value string) error {
  type httpHeader (line 127) | type httpHeader struct
  type HTTPHeaders (line 133) | type HTTPHeaders
    method String (line 135) | func (h *HTTPHeaders) String() string {
    method Set (line 140) | func (h *HTTPHeaders) Set(value string) error {
  type httpParam (line 156) | type httpParam struct
  type HTTPParams (line 162) | type HTTPParams
    method String (line 164) | func (h *HTTPParams) String() string {
    method Set (line 169) | func (h *HTTPParams) Set(value string) error {
  type HTTPMethods (line 189) | type HTTPMethods
    method String (line 191) | func (h *HTTPMethods) String() string {
    method Set (line 196) | func (h *HTTPMethods) Set(value string) error {
  type urlRewrite (line 202) | type urlRewrite struct
  type URLRewriteMap (line 208) | type URLRewriteMap
    method String (line 210) | func (r *URLRewriteMap) String() string {
    method Set (line 215) | func (r *URLRewriteMap) Set(value string) error {
  type headerRewrite (line 229) | type headerRewrite struct
  type HeaderRewriteMap (line 236) | type HeaderRewriteMap
    method String (line 238) | func (r *HeaderRewriteMap) String() string {
    method Set (line 243) | func (r *HeaderRewriteMap) Set(value string) error {
  type urlRegexp (line 265) | type urlRegexp struct
  type HTTPURLRegexp (line 270) | type HTTPURLRegexp
    method String (line 272) | func (r *HTTPURLRegexp) String() string {
    method Set (line 277) | func (r *HTTPURLRegexp) Set(value string) error {

FILE: http_modifier_settings_test.go
  function TestHTTPHeaderFilters (line 7) | func TestHTTPHeaderFilters(t *testing.T) {
  function TestHTTPHashFilters (line 27) | func TestHTTPHashFilters(t *testing.T) {
  function TestUrlRewriteMap (line 54) | func TestUrlRewriteMap(t *testing.T) {

FILE: http_modifier_test.go
  function TestHTTPModifierWithoutConfig (line 9) | func TestHTTPModifierWithoutConfig(t *testing.T) {
  function TestHTTPModifierHeaderFilters (line 15) | func TestHTTPModifierHeaderFilters(t *testing.T) {
  function TestHTTPModifierHeaderNegativeFilters (line 42) | func TestHTTPModifierHeaderNegativeFilters(t *testing.T) {
  function TestHTTPHeaderBasicAuthFilters (line 81) | func TestHTTPHeaderBasicAuthFilters(t *testing.T) {
  function TestHTTPModifierURLRewrite (line 120) | func TestHTTPModifierURLRewrite(t *testing.T) {
  function TestHTTPModifierHeaderRewrite (line 149) | func TestHTTPModifierHeaderRewrite(t *testing.T) {
  function TestHTTPModifierHeaderHashFilters (line 170) | func TestHTTPModifierHeaderHashFilters(t *testing.T) {
  function TestHTTPModifierParamHashFilters (line 195) | func TestHTTPModifierParamHashFilters(t *testing.T) {
  function TestHTTPModifierHeaders (line 220) | func TestHTTPModifierHeaders(t *testing.T) {
  function TestHTTPModifierURLRegexp (line 237) | func TestHTTPModifierURLRegexp(t *testing.T) {
  function TestHTTPModifierURLNegativeRegexp (line 263) | func TestHTTPModifierURLNegativeRegexp(t *testing.T) {
  function TestHTTPModifierSetHeader (line 289) | func TestHTTPModifierSetHeader(t *testing.T) {
  function TestHTTPModifierSetParam (line 305) | func TestHTTPModifierSetParam(t *testing.T) {

FILE: http_prettifier.go
  function prettifyHTTP (line 13) | func prettifyHTTP(p []byte) []byte {

FILE: http_prettifier_test.go
  function TestHTTPPrettifierGzip (line 11) | func TestHTTPPrettifierGzip(t *testing.T) {
  function TestHTTPPrettifierChunked (line 29) | func TestHTTPPrettifierChunked(t *testing.T) {

FILE: input_dummy.go
  type DummyInput (line 8) | type DummyInput struct
    method PluginRead (line 25) | func (i *DummyInput) PluginRead() (*Message, error) {
    method emit (line 36) | func (i *DummyInput) emit() {
    method String (line 49) | func (i *DummyInput) String() string {
    method Close (line 54) | func (i *DummyInput) Close() error {
  function NewDummyInput (line 14) | func NewDummyInput(options string) (di *DummyInput) {

FILE: input_file.go
  type filePayload (line 26) | type filePayload struct
  type payloadQueue (line 32) | type payloadQueue struct
    method Len (line 37) | func (h payloadQueue) Len() int           { return len(h.s) }
    method Less (line 38) | func (h payloadQueue) Less(i, j int) bool { return h.s[i].timestamp < ...
    method Swap (line 39) | func (h payloadQueue) Swap(i, j int)      { h.s[i], h.s[j] = h.s[j], h...
    method Push (line 41) | func (h *payloadQueue) Push(x interface{}) {
    method Pop (line 47) | func (h *payloadQueue) Pop() interface{} {
    method Idx (line 55) | func (h payloadQueue) Idx(i int) *filePayload {
  type fileInputReader (line 59) | type fileInputReader struct
    method parse (line 70) | func (f *fileInputReader) parse(init chan struct{}) error {
    method wait (line 139) | func (f *fileInputReader) wait() {
    method Close (line 158) | func (f *fileInputReader) Close() error {
  function newFileInputReader (line 167) | func newFileInputReader(path string, readDepth int, dryRun bool) *fileIn...
  type FileInput (line 204) | type FileInput struct
    method init (line 251) | func (i *FileInput) init() (err error) {
    method PluginRead (line 299) | func (i *FileInput) PluginRead() (*Message, error) {
    method String (line 311) | func (i *FileInput) String() string {
    method nextReader (line 316) | func (i *FileInput) nextReader() (next *fileInputReader) {
    method emit (line 337) | func (i *FileInput) emit() {
    method Close (line 440) | func (i *FileInput) Close() error {
  function NewFileInput (line 220) | func NewFileInput(path string, loop bool, readDepth int, maxWait time.Du...
  function parseS3Url (line 241) | func parseS3Url(path string) (bucket, key string) {

FILE: input_file_test.go
  function TestInputFileWithGET (line 15) | func TestInputFileWithGET(t *testing.T) {
  function TestInputFileWithPayloadLargerThan64Kb (line 38) | func TestInputFileWithPayloadLargerThan64Kb(t *testing.T) {
  function TestInputFileWithGETAndPOST (line 62) | func TestInputFileWithGETAndPOST(t *testing.T) {
  function TestInputFileMultipleFilesWithRequestsOnly (line 90) | func TestInputFileMultipleFilesWithRequestsOnly(t *testing.T) {
  function TestInputFileRequestsWithLatency (line 120) | func TestInputFileRequestsWithLatency(t *testing.T) {
  function TestInputFileMultipleFilesWithRequestsAndResponses (line 148) | func TestInputFileMultipleFilesWithRequestsAndResponses(t *testing.T) {
  function TestInputFileLoop (line 191) | func TestInputFileLoop(t *testing.T) {
  function TestInputFileCompressed (line 212) | func TestInputFileCompressed(t *testing.T) {
  type CaptureFile (line 238) | type CaptureFile struct
    method TearDown (line 250) | func (expectedCaptureFile *CaptureFile) TearDown() {
    method PayloadsEqual (line 271) | func (expectedCaptureFile *CaptureFile) PayloadsEqual(other []*Message...
  function NewExpectedCaptureFile (line 243) | func NewExpectedCaptureFile(msgs []*Message, file *os.File) *CaptureFile {
  type RequestGenerator (line 256) | type RequestGenerator struct
  function NewRequestGenerator (line 262) | func NewRequestGenerator(inputs []PluginReader, emit func(), count int) ...
  function CreateCaptureFile (line 290) | func CreateCaptureFile(requestGenerator *RequestGenerator) *CaptureFile {
  function ReadFromCaptureFile (line 326) | func ReadFromCaptureFile(captureFile *os.File, count int, callback write...

FILE: input_http.go
  type HTTPInput (line 12) | type HTTPInput struct
    method PluginRead (line 31) | func (i *HTTPInput) PluginRead() (*Message, error) {
    method Close (line 44) | func (i *HTTPInput) Close() error {
    method handler (line 49) | func (i *HTTPInput) handler(w http.ResponseWriter, r *http.Request) {
    method listen (line 58) | func (i *HTTPInput) listen(address string) {
    method String (line 79) | func (i *HTTPInput) String() string {
  function NewHTTPInput (line 20) | func NewHTTPInput(address string) (i *HTTPInput) {

FILE: input_http_test.go
  function TestHTTPInput (line 12) | func TestHTTPInput(t *testing.T) {
  function TestInputHTTPLargePayload (line 41) | func TestInputHTTPLargePayload(t *testing.T) {

FILE: input_kafka.go
  type KafkaInput (line 16) | type KafkaInput struct
    method ErrorHandler (line 88) | func (i *KafkaInput) ErrorHandler(consumer sarama.PartitionConsumer) {
    method PluginRead (line 95) | func (i *KafkaInput) PluginRead() (*Message, error) {
    method String (line 133) | func (i *KafkaInput) String() string {
    method Close (line 138) | func (i *KafkaInput) Close() error {
    method timeWait (line 143) | func (i *KafkaInput) timeWait(curInputTs string) {
  function getOffsetOfPartitions (line 25) | func getOffsetOfPartitions(offsetCfg string) int64 {
  function NewKafkaInput (line 34) | func NewKafkaInput(offsetCfg string, config *InputKafkaConfig, tlsConfig...
  type kafkaTimer (line 180) | type kafkaTimer struct

FILE: input_kafka_test.go
  function TestInputKafkaRAW (line 10) | func TestInputKafkaRAW(t *testing.T) {
  function TestInputKafkaJSON (line 36) | func TestInputKafkaJSON(t *testing.T) {

FILE: input_raw.go
  type RAWInput (line 20) | type RAWInput struct
    method PluginRead (line 83) | func (i *RAWInput) PluginRead() (*Message, error) {
    method listen (line 118) | func (i *RAWInput) listen(address string) {
    method String (line 141) | func (i *RAWInput) String() string {
    method GetStats (line 146) | func (i *RAWInput) GetStats() []tcp.Stats {
    method Close (line 156) | func (i *RAWInput) Close() error {
    method addStats (line 168) | func (i *RAWInput) addStats(mStats tcp.Stats) {
  function NewRAWInput (line 35) | func NewRAWInput(address string, config RAWInputConfig) (i *RAWInput) {

FILE: input_raw_test.go
  constant testRawExpire (line 21) | testRawExpire = time.Millisecond * 200
  function TestRAWInputIPv4 (line 23) | func TestRAWInputIPv4(t *testing.T) {
  function TestRAWInputNoKeepAlive (line 94) | func TestRAWInputNoKeepAlive(t *testing.T) {
  function TestRAWInputIPv6 (line 160) | func TestRAWInputIPv6(t *testing.T) {
  function TestInputRAWChunkedEncoding (line 222) | func TestInputRAWChunkedEncoding(t *testing.T) {
  function BenchmarkRAWInputWithReplay (line 281) | func BenchmarkRAWInputWithReplay(b *testing.B) {

FILE: input_tcp.go
  type TCPInput (line 14) | type TCPInput struct
    method PluginRead (line 43) | func (i *TCPInput) PluginRead() (msg *Message, err error) {
    method Close (line 54) | func (i *TCPInput) Close() error {
    method listen (line 60) | func (i *TCPInput) listen(address string) {
    method handleConnection (line 100) | func (i *TCPInput) handleConnection(conn net.Conn) {
    method String (line 131) | func (i *TCPInput) String() string {
  type TCPInputConfig (line 23) | type TCPInputConfig struct
  function NewTCPInput (line 30) | func NewTCPInput(address string, config *TCPInputConfig) (i *TCPInput) {
  function isTemporaryNetworkError (line 135) | func isTemporaryNetworkError(err error) bool {

FILE: input_tcp_test.go
  function TestTCPInput (line 20) | func TestTCPInput(t *testing.T) {
  function genCertificate (line 64) | func genCertificate(template *x509.Certificate) ([]byte, []byte) {
  function TestTCPInputSecure (line 83) | func TestTCPInputSecure(t *testing.T) {

FILE: internal/byteutils/byteutils.go
  function Cut (line 9) | func Cut(a []byte, from, to int) []byte {
  function Insert (line 17) | func Insert(a []byte, i int, b []byte) []byte {
  function Replace (line 26) | func Replace(a []byte, from, to int, new []byte) []byte {
  function SliceToString (line 50) | func SliceToString(buf []byte) string {

FILE: internal/byteutils/byteutils_test.go
  function TestCut (line 8) | func TestCut(t *testing.T) {
  function TestInsert (line 14) | func TestInsert(t *testing.T) {
  function TestReplace (line 20) | func TestReplace(t *testing.T) {
  function BenchmarkStringtoSlice (line 34) | func BenchmarkStringtoSlice(b *testing.B) {

FILE: internal/capture/af_packet.go
  function newAfpacketHandle (line 12) | func newAfpacketHandle(device string, snaplen int, block_size int, num_b...
  function afpacketComputeSize (line 17) | func afpacketComputeSize(targetSizeMb int, snaplen int, pageSize int) (
  type afpacketHandle (line 22) | type afpacketHandle struct
    method ReadPacketData (line 25) | func (h *afpacketHandle) ReadPacketData() (data []byte, ci gopacket.Ca...
    method SetBPFFilter (line 30) | func (h *afpacketHandle) SetBPFFilter(filter string, snaplen int) (err...

FILE: internal/capture/af_packet_linux.go
  type afpacketHandle (line 18) | type afpacketHandle struct
    method ReadPacketData (line 52) | func (h *afpacketHandle) ReadPacketData() (data []byte, ci gopacket.Ca...
    method SetBPFFilter (line 57) | func (h *afpacketHandle) SetBPFFilter(filter string, snaplen int) (err...
    method LinkType (line 79) | func (h *afpacketHandle) LinkType() layers.LinkType {
    method Close (line 84) | func (h *afpacketHandle) Close() {
    method SocketStats (line 89) | func (h *afpacketHandle) SocketStats() (as afpacket.SocketStats, asv a...
  function newAfpacketHandle (line 22) | func newAfpacketHandle(device string, snaplen int, block_size int, num_b...
  function afpacketComputeSize (line 97) | func afpacketComputeSize(targetSizeMb int, snaplen int, pageSize int) (

FILE: internal/capture/capture.go
  function init (line 32) | func init() {
  type PacketHandler (line 38) | type PacketHandler
  type PcapStatProvider (line 40) | type PcapStatProvider interface
  type PcapSetFilter (line 44) | type PcapSetFilter interface
  type PcapOptions (line 50) | type PcapOptions struct
  type Listener (line 74) | type Listener struct
    method Listen (line 198) | func (l *Listener) Listen(ctx context.Context) (err error) {
    method ListenBackground (line 276) | func (l *Listener) ListenBackground(ctx context.Context) chan error {
    method Filter (line 352) | func (l *Listener) Filter(ifi pcap.Interface, hosts ...string) (filter...
    method PcapHandle (line 403) | func (l *Listener) PcapHandle(ifi pcap.Interface) (handle *pcap.Handle...
    method SocketHandle (line 482) | func (l *Listener) SocketHandle(ifi pcap.Interface) (handle Socket, er...
    method readHandle (line 524) | func (l *Listener) readHandle(key string, hndl packetHandle) {
    method Messages (line 598) | func (l *Listener) Messages() chan *tcp.Message {
    method closeHandles (line 602) | func (l *Listener) closeHandles(key string) {
    method activatePcap (line 617) | func (l *Listener) activatePcap() error {
    method activateVxLanSocket (line 642) | func (l *Listener) activateVxLanSocket() error {
    method activateRawSocket (line 654) | func (l *Listener) activateRawSocket() error {
    method activatePcapFile (line 682) | func (l *Listener) activatePcapFile() (err error) {
    method activateAFPacket (line 707) | func (l *Listener) activateAFPacket() error {
    method setInterfaces (line 745) | func (l *Listener) setInterfaces() (err error) {
  type packetHandle (line 94) | type packetHandle struct
  type EngineType (line 100) | type EngineType
    method Set (line 112) | func (eng *EngineType) Set(v string) error {
    method String (line 130) | func (eng *EngineType) String() (e string) {
  constant EnginePcap (line 104) | EnginePcap EngineType = 1 << iota
  constant EnginePcapFile (line 105) | EnginePcapFile
  constant EngineRawSocket (line 106) | EngineRawSocket
  constant EngineAFPacket (line 107) | EngineAFPacket
  constant EngineVXLAN (line 108) | EngineVXLAN
  function NewListener (line 151) | func NewListener(host string, ports []uint16, config PcapOptions) (l *Li...
  function k8sIPs (line 294) | func k8sIPs(addr string) []string {
  function http1StartHint (line 502) | func http1StartHint(pckt *tcp.Packet) (isRequest, isResponse bool) {
  function http1EndHint (line 515) | func http1EndHint(m *tcp.Message) bool {
  function isDevice (line 816) | func isDevice(addr string, ifi pcap.Interface) bool {
  function interfaceAddresses (line 841) | func interfaceAddresses(ifi pcap.Interface) []string {
  function interfaceIPs (line 849) | func interfaceIPs(ifi pcap.Interface) []net.IP {
  function listenAll (line 857) | func listenAll(addr string) bool {
  function portsFilter (line 865) | func portsFilter(transport string, direction string, ports []uint16) str...
  function hostsFilter (line 877) | func hostsFilter(direction string, hosts []string) string {
  function pcapLinkTypeLength (line 886) | func pcapLinkTypeLength(lType int, vlan bool) (int, bool) {

FILE: internal/capture/capture_test.go
  function TestSetInterfaces (line 7) | func TestSetInterfaces(t *testing.T) {

FILE: internal/capture/dump.go
  type Writer (line 21) | type Writer struct
    method WriteFileHeader (line 77) | func (w *Writer) WriteFileHeader(snaplen uint32, linktype layers.LinkT...
    method writePacketHeader (line 98) | func (w *Writer) writePacketHeader(ci gopacket.CaptureInfo) error {
    method WritePacket (line 114) | func (w *Writer) WritePacket(ci gopacket.CaptureInfo, data []byte) err...
  constant magicNanoseconds (line 28) | magicNanoseconds = 0xA1B23C4D
  constant magicMicroseconds (line 29) | magicMicroseconds = 0xA1B2C3D4
  constant versionMajor (line 30) | versionMajor = 2
  constant versionMinor (line 31) | versionMinor = 4
  function NewWriterNanos (line 50) | func NewWriterNanos(w io.Writer) *Writer {
  function NewWriter (line 71) | func NewWriter(w io.Writer) *Writer {
  constant nanosPerMicro (line 95) | nanosPerMicro = 1000
  constant nanosPerNano (line 96) | nanosPerNano = 1

FILE: internal/capture/sock_linux.go
  constant ETHALL (line 21) | ETHALL uint16 = unix.ETH_P_ALL<<8 | unix.ETH_P_ALL>>8
  constant BLOCKSIZE (line 23) | BLOCKSIZE = 64 << 10
  constant BLOCKNR (line 25) | BLOCKNR = (2 << 20) / BLOCKSIZE
  constant FRAMESIZE (line 27) | FRAMESIZE = BLOCKSIZE
  constant FRAMENR (line 29) | FRAMENR = BLOCKNR * BLOCKSIZE / FRAMESIZE
  constant MAPHUGE2MB (line 31) | MAPHUGE2MB = 21 << unix.MAP_HUGE_SHIFT
  type SockRaw (line 37) | type SockRaw struct
    method ReadPacketData (line 129) | func (sock *SockRaw) ReadPacketData() (buf []byte, ci gopacket.Capture...
    method Close (line 171) | func (sock *SockRaw) Close() (err error) {
    method SetSnapLen (line 185) | func (sock *SockRaw) SetSnapLen(snap int) error {
    method SetTimeout (line 200) | func (sock *SockRaw) SetTimeout(t time.Duration) error {
    method GetSnapLen (line 208) | func (sock *SockRaw) GetSnapLen() int {
    method SetBPFFilter (line 215) | func (sock *SockRaw) SetBPFFilter(expr string) error {
    method SetPromiscuous (line 240) | func (sock *SockRaw) SetPromiscuous(b bool) error {
    method Stats (line 257) | func (sock *SockRaw) Stats() (*unix.TpacketStats, error) {
    method SetLoopbackIndex (line 264) | func (sock *SockRaw) SetLoopbackIndex(i int32) {
    method WritePacketData (line 271) | func (sock *SockRaw) WritePacketData(pkt []byte) error {
  function NewSocket (line 49) | func NewSocket(pifi pcap.Interface) (*SockRaw, error) {
  function tpAlign (line 276) | func tpAlign(x int) int {

FILE: internal/capture/sock_others.go
  function NewSocket (line 12) | func NewSocket(_ pcap.Interface) (Socket, error) {

FILE: internal/capture/socket.go
  type Socket (line 10) | type Socket interface

FILE: internal/capture/vxlan.go
  constant VxLanPacketSize (line 12) | VxLanPacketSize = 1526
  type vxlanHandle (line 14) | type vxlanHandle struct
    method reader (line 43) | func (v *vxlanHandle) reader() {
    method vniIsAllowed (line 67) | func (v *vxlanHandle) vniIsAllowed(packet gopacket.Packet) bool {
    method ReadPacketData (line 87) | func (v *vxlanHandle) ReadPacketData() ([]byte, gopacket.CaptureInfo, ...
    method Close (line 95) | func (v *vxlanHandle) Close() error {
  function newVXLANHandler (line 20) | func newVXLANHandler(port int, vnis []int) (*vxlanHandle, error) {

FILE: internal/ring/ring.go
  function roundUp (line 25) | func roundUp(v uint64) uint64 {
  type node (line 37) | type node struct
  type nodes (line 42) | type nodes
  type RingBuffer (line 50) | type RingBuffer struct
    method init (line 61) | func (rb *RingBuffer) init(size uint64) {
    method Put (line 73) | func (rb *RingBuffer) Put(item interface{}) error {
    method Offer (line 81) | func (rb *RingBuffer) Offer(item interface{}) (bool, error) {
    method put (line 85) | func (rb *RingBuffer) put(item interface{}, offer bool) (bool, error) {
    method Get (line 123) | func (rb *RingBuffer) Get() (interface{}, error) {
    method Poll (line 132) | func (rb *RingBuffer) Poll(timeout time.Duration) (interface{}, error) {
    method Len (line 177) | func (rb *RingBuffer) Len() uint64 {
    method Cap (line 182) | func (rb *RingBuffer) Cap() uint64 {
    method Dispose (line 189) | func (rb *RingBuffer) Dispose() {
    method IsDisposed (line 195) | func (rb *RingBuffer) IsDisposed() bool {
  function NewRingBuffer (line 201) | func NewRingBuffer(size uint64) *RingBuffer {

FILE: internal/simpletime/time.go
  function init (line 9) | func init() {

FILE: internal/size/size.go
  type Size (line 10) | type Size
    method Set (line 22) | func (siz *Size) Set(size string) (err error) {
    method String (line 62) | func (siz *Size) String() string {

FILE: internal/size/size_test.go
  function TestParseDataUnit (line 5) | func TestParseDataUnit(t *testing.T) {

FILE: internal/tcp/tcp_message.go
  type TCPProtocol (line 16) | type TCPProtocol
    method Set (line 26) | func (protocol *TCPProtocol) Set(v string) error {
    method String (line 38) | func (protocol *TCPProtocol) String() string {
  constant ProtocolHTTP (line 20) | ProtocolHTTP TCPProtocol = iota
  constant ProtocolBinary (line 22) | ProtocolBinary
  type Stats (line 50) | type Stats struct
  type Message (line 64) | type Message struct
    method UUID (line 73) | func (m *Message) UUID() []byte {
    method add (line 101) | func (m *Message) add(packet *Packet) bool {
    method Packets (line 134) | func (m *Message) Packets() []*Packet {
    method MissingChunk (line 138) | func (m *Message) MissingChunk() bool {
    method PacketData (line 152) | func (m *Message) PacketData() [][]byte {
    method Data (line 163) | func (m *Message) Data() []byte {
    method SetProtocolState (line 182) | func (m *Message) SetProtocolState(feedback interface{}) {
    method ProtocolState (line 187) | func (m *Message) ProtocolState() interface{} {
    method Sort (line 192) | func (m *Message) Sort() {
  type Emitter (line 197) | type Emitter
  type HintEnd (line 201) | type HintEnd
  type HintStart (line 205) | type HintStart
  type MessageParser (line 209) | type MessageParser struct
    method PacketHandler (line 256) | func (parser *MessageParser) PacketHandler(packet *PcapPacket) {
    method wait (line 261) | func (parser *MessageParser) wait() {
    method parsePacket (line 281) | func (parser *MessageParser) parsePacket(pcapPkt *PcapPacket) *Packet {
    method processPacket (line 315) | func (parser *MessageParser) processPacket(pckt *Packet) {
    method addPacket (line 358) | func (parser *MessageParser) addPacket(m *Message, pckt *Packet) bool {
    method Fix100Continue (line 377) | func (parser *MessageParser) Fix100Continue(m *Message) {
    method Read (line 400) | func (parser *MessageParser) Read() *Message {
    method Emit (line 405) | func (parser *MessageParser) Emit(m *Message) {
    method timer (line 419) | func (parser *MessageParser) timer(now time.Time) {
    method Close (line 439) | func (parser *MessageParser) Close() error {
  function NewMessageParser (line 225) | func NewMessageParser(messages chan *Message, ports []uint16, ips []net....
  function containsOrEmpty (line 303) | func containsOrEmpty(element net.IP, ipList []net.IP) bool {
  function GetUnexportedField (line 413) | func GetUnexportedField(field reflect.Value) interface{} {

FILE: internal/tcp/tcp_packet.go
  function copySlice (line 13) | func copySlice(to []byte, skip int, from ...[]byte) ([]byte, int) {
  function init (line 35) | func init() {
  type Dir (line 45) | type Dir
  constant DirUnknown (line 48) | DirUnknown = iota
  constant DirIncoming (line 49) | DirIncoming
  constant DirOutcoming (line 50) | DirOutcoming
  type Packet (line 59) | type Packet struct
    method parse (line 95) | func (pckt *Packet) parse(data []byte, lType, lTypeLen int, cp *gopack...
    method MessageID (line 215) | func (pckt *Packet) MessageID() uint64 {
    method Src (line 226) | func (pckt *Packet) Src() string {
    method Dst (line 231) | func (pckt *Packet) Dst() string {
  type PcapPacket (line 78) | type PcapPacket struct
  function ParsePacket (line 86) | func ParsePacket(data []byte, lType, lTypeLen int, ci *gopacket.CaptureI...
  type EmptyPacket (line 235) | type EmptyPacket
    method Error (line 237) | func (err EmptyPacket) Error() string {
  type ErrHdrLength (line 242) | type ErrHdrLength
    method Error (line 244) | func (err ErrHdrLength) Error() string {
  type ErrHdrMissing (line 249) | type ErrHdrMissing
    method Error (line 251) | func (err ErrHdrMissing) Error() string {
  type ErrHdrExpected (line 256) | type ErrHdrExpected
    method Error (line 258) | func (err ErrHdrExpected) Error() string {
  type ErrHdrInvalid (line 263) | type ErrHdrInvalid
    method Error (line 265) | func (err ErrHdrInvalid) Error() string {
  function ipv6ExtensionHdr (line 270) | func ipv6ExtensionHdr(b byte) bool {
  function ip2int (line 275) | func ip2int(ip net.IP) uint32 {

FILE: internal/tcp/tcp_test.go
  function generateHeader (line 18) | func generateHeader(request bool, seq uint32, length uint16) []byte {
  function GetPackets (line 44) | func GetPackets(request bool, start uint32, _len int, payload []byte) []...
  function TestRequestResponseMapping (line 64) | func TestRequestResponseMapping(t *testing.T) {
  function TestMessageParserWithHint (line 111) | func TestMessageParserWithHint(t *testing.T) {
  function TestMessageParserWrongOrder (line 156) | func TestMessageParserWrongOrder(t *testing.T) {
  function TestMessageParserWithoutHint (line 200) | func TestMessageParserWithoutHint(t *testing.T) {
  function TestMessageTimeoutReached (line 215) | func TestMessageTimeoutReached(t *testing.T) {
  function BenchmarkMessageUUID (line 234) | func BenchmarkMessageUUID(b *testing.B) {
  function BenchmarkPacketParseAndSort (line 252) | func BenchmarkPacketParseAndSort(b *testing.B) {
  function BenchmarkMessageParserWithoutHint (line 264) | func BenchmarkMessageParserWithoutHint(b *testing.B) {
  function BenchmarkMessageParserWithHint (line 278) | func BenchmarkMessageParserWithHint(b *testing.B) {
  function BenchmarkNewAndParsePacket (line 309) | func BenchmarkNewAndParsePacket(b *testing.B) {

FILE: kafka.go
  type SASLKafkaConfig (line 20) | type SASLKafkaConfig struct
  type InputKafkaConfig (line 29) | type InputKafkaConfig struct
  type OutputKafkaConfig (line 39) | type OutputKafkaConfig struct
  type KafkaTLSConfig (line 48) | type KafkaTLSConfig struct
  type KafkaMessage (line 56) | type KafkaMessage struct
    method Dump (line 126) | func (m KafkaMessage) Dump() ([]byte, error) {
  function NewTLSConfig (line 67) | func NewTLSConfig(clientCertFile, clientKeyFile, caCertFile string) (*tl...
  function NewKafkaConfig (line 98) | func NewKafkaConfig(saslConfig *SASLKafkaConfig, tlsConfig *KafkaTLSConf...
  type XDGSCRAMClient (line 151) | type XDGSCRAMClient struct
    method Begin (line 158) | func (x *XDGSCRAMClient) Begin(userName, password, authzID string) (er...
    method Step (line 168) | func (x *XDGSCRAMClient) Step(challenge string) (response string, err ...
    method Done (line 174) | func (x *XDGSCRAMClient) Done() bool {

FILE: limiter.go
  type Limiter (line 13) | type Limiter struct
    method isLimitedExceptions (line 63) | func (l *Limiter) isLimitedExceptions() bool {
    method isLimited (line 78) | func (l *Limiter) isLimited() bool {
    method PluginWrite (line 102) | func (l *Limiter) PluginWrite(msg *Message) (n int, err error) {
    method PluginRead (line 114) | func (l *Limiter) PluginRead() (msg *Message, err error) {
    method String (line 129) | func (l *Limiter) String() string {
    method Close (line 134) | func (l *Limiter) Close() error {
  function parseLimitOptions (line 22) | func parseLimitOptions(options string) (limit int, isPercent bool) {
  function newLimiterExceptions (line 34) | func newLimiterExceptions(l *Limiter) {
  function NewLimiter (line 52) | func NewLimiter(plugin interface{}, options string) PluginReadWriter {

FILE: limiter_test.go
  function TestOutputLimiter (line 10) | func TestOutputLimiter(t *testing.T) {
  function TestInputLimiter (line 36) | func TestInputLimiter(t *testing.T) {
  function TestPercentLimiter1 (line 63) | func TestPercentLimiter1(t *testing.T) {
  function TestPercentLimiter2 (line 88) | func TestPercentLimiter2(t *testing.T) {

FILE: middleware.go
  type Middleware (line 17) | type Middleware struct
    method ReadFrom (line 68) | func (m *Middleware) ReadFrom(plugin PluginReader) {
    method copy (line 73) | func (m *Middleware) copy(to io.Writer, from PluginReader) {
    method read (line 107) | func (m *Middleware) read(from io.Reader) {
    method PluginRead (line 135) | func (m *Middleware) PluginRead() (msg *Message, err error) {
    method String (line 145) | func (m *Middleware) String() string {
    method isClosed (line 149) | func (m *Middleware) isClosed() bool {
    method Close (line 156) | func (m *Middleware) Close() error {
  function NewMiddleware (line 29) | func NewMiddleware(command string) *Middleware {

FILE: middleware/middleware.js
  function init (line 11) | function init() {
  function parseMessage (line 105) | function parseMessage(msg) {
  function searchResponses (line 147) | function searchResponses(id, searchPattern, callback) {
  function httpMethod (line 204) | function httpMethod(payload) {
  function httpPath (line 209) | function httpPath(payload) {
  function setHttpPath (line 215) | function setHttpPath(payload, newPath) {
  function httpPathParam (line 222) | function httpPathParam(payload, name) {
  function setHttpPathParam (line 230) | function setHttpPathParam(payload, name, value) {
  function httpStatus (line 250) | function httpStatus(payload) {
  function setHttpStatus (line 254) | function setHttpStatus(payload, newStatus) {
  function httpHeaders (line 258) | function httpHeaders(payload) {
  function httpHeader (line 273) | function httpHeader(payload, name) {
  function setHttpHeader (line 317) | function setHttpHeader(payload, name, value) {
  function deleteHttpHeader (line 327) | function deleteHttpHeader(payload, name) {
  function httpBody (line 337) | function httpBody(payload) {
  function setHttpBody (line 346) | function setHttpBody(payload, newBody) {
  function httpBodyParam (line 352) | function httpBodyParam(payload, name) {
  function setHttpBodyParam (line 363) | function setHttpBodyParam(payload, name, value) {
  function setHttpCookie (line 381) | function setHttpCookie(payload, name, value) {
  function deleteHttpCookie (line 389) | function deleteHttpCookie(payload, name) {
  function httpCookie (line 396) | function httpCookie(payload, name) {
  function testRunner (line 438) | function testRunner(){
  function testBenchmark (line 446) | function testBenchmark(){
  function fail (line 481) | function fail(message) {
  function log (line 485) | function log(message) {
  function TEST_init (line 489) | function TEST_init() {
  function TEST_filter (line 525) | function TEST_filter() {
  function TEST_parseMessage (line 553) | function TEST_parseMessage() {
  function TEST_httpPath (line 565) | function TEST_httpPath() {
  function TEST_httpMethod (line 586) | function TEST_httpMethod() {
  function TEST_httpPathParam (line 598) | function TEST_httpPathParam() {
  function TEST_httpBodyParam (line 629) | function TEST_httpBodyParam() {
  function TEST_httpHeader (line 660) | function TEST_httpHeader() {
  function TEST_setHttpHeader (line 678) | function TEST_setHttpHeader() {
  function TEST_deleteHttpHeader (line 700) | function TEST_deleteHttpHeader() {
  function TEST_httpBody (line 712) | function TEST_httpBody() {
  function TEST_setHttpBody (line 726) | function TEST_setHttpBody() {
  function TEST_httpCookie (line 735) | function TEST_httpCookie() {
  function TEST_setHttpCookie (line 748) | function TEST_setHttpCookie() {
  function TEST_deleteHttpCookie (line 761) | function TEST_deleteHttpCookie() {
  function TEST_httpHeaders (line 770) | function TEST_httpHeaders() {

FILE: middleware_test.go
  constant echoSh (line 14) | echoSh = "./examples/middleware/echo.sh"
  constant tokenModifier (line 15) | tokenModifier = "go run ./examples/middleware/token_modifier.go"
  function initMiddleware (line 19) | func initMiddleware(cmd *exec.Cmd, cancl context.CancelFunc, l PluginRea...
  function initCmd (line 42) | func initCmd(command string, env []string) (*exec.Cmd, context.CancelFun...
  function TestMiddlewareEarlyClose (line 50) | func TestMiddlewareEarlyClose(t *testing.T) {

FILE: output_binary.go
  type BinaryOutputConfig (line 15) | type BinaryOutputConfig struct
  type BinaryOutput (line 26) | type BinaryOutput struct
    method PluginWrite (line 37) | func (o *BinaryOutput) PluginWrite(msg *Message) (n int, err error) {
    method PluginRead (line 42) | func (o *BinaryOutput) PluginRead() (*Message, error) {
    method String (line 46) | func (o *BinaryOutput) String() string {
    method Close (line 51) | func (o *BinaryOutput) Close() error {
  function NewBinaryOutput (line 32) | func NewBinaryOutput(address string, config *BinaryOutputConfig) PluginR...

FILE: output_binary_pro.go
  type BinaryOutputConfig (line 15) | type BinaryOutputConfig struct
  type BinaryOutput (line 26) | type BinaryOutput struct
    method workerMaster (line 65) | func (o *BinaryOutput) workerMaster() {
    method startWorker (line 79) | func (o *BinaryOutput) startWorker() {
    method PluginWrite (line 117) | func (o *BinaryOutput) PluginWrite(msg *Message) (n int, err error) {
    method PluginRead (line 136) | func (o *BinaryOutput) PluginRead() (*Message, error) {
    method sendRequest (line 150) | func (o *BinaryOutput) sendRequest(client *TCPClient, msg *Message) {
    method String (line 170) | func (o *BinaryOutput) String() string {
    method Close (line 175) | func (o *BinaryOutput) Close() error {
  function NewBinaryOutput (line 42) | func NewBinaryOutput(address string, config *BinaryOutputConfig) PluginR...

FILE: output_dummy.go
  type DummyOutput (line 8) | type DummyOutput struct
    method PluginWrite (line 19) | func (i *DummyOutput) PluginWrite(msg *Message) (int, error) {
    method String (line 31) | func (i *DummyOutput) String() string {
  function NewDummyOutput (line 12) | func NewDummyOutput() (di *DummyOutput) {

FILE: output_file.go
  function init (line 25) | func init() {
  function randSeq (line 29) | func randSeq(n int) string {
  type FileOutputConfig (line 51) | type FileOutputConfig struct
  type FileOutput (line 62) | type FileOutput struct
    method filename (line 159) | func (o *FileOutput) filename() string {
    method updateName (line 205) | func (o *FileOutput) updateName() {
    method PluginWrite (line 213) | func (o *FileOutput) PluginWrite(msg *Message) (n int, err error) {
    method flush (line 263) | func (o *FileOutput) flush() {
    method String (line 289) | func (o *FileOutput) String() string {
    method closeLocked (line 293) | func (o *FileOutput) closeLocked() error {
    method Close (line 314) | func (o *FileOutput) Close() error {
    method IsClosed (line 321) | func (o *FileOutput) IsClosed() bool {
  function NewFileOutput (line 80) | func NewFileOutput(pathTemplate string, config *FileOutputConfig) *FileO...
  function getFileIndex (line 106) | func getFileIndex(name string) int {
  function setFileIndex (line 119) | func setFileIndex(name string, idx int) string {
  function withoutIndex (line 133) | func withoutIndex(s string) string {
  type sortByFileIndex (line 141) | type sortByFileIndex
    method Len (line 143) | func (s sortByFileIndex) Len() int {
    method Swap (line 147) | func (s sortByFileIndex) Swap(i, j int) {
    method Less (line 151) | func (s sortByFileIndex) Less(i, j int) bool {

FILE: output_file_test.go
  function TestFileOutput (line 16) | func TestFileOutput(t *testing.T) {
  function TestFileOutputWithNameCleaning (line 60) | func TestFileOutputWithNameCleaning(t *testing.T) {
  function TestFileOutputPathTemplate (line 71) | func TestFileOutputPathTemplate(t *testing.T) {
  function TestFileOutputMultipleFiles (line 83) | func TestFileOutputMultipleFiles(t *testing.T) {
  function TestFileOutputFilePerRequest (line 114) | func TestFileOutputFilePerRequest(t *testing.T) {
  function TestFileOutputCompression (line 142) | func TestFileOutputCompression(t *testing.T) {
  function TestGetFileIndex (line 164) | func TestGetFileIndex(t *testing.T) {
  function TestSetFileIndex (line 182) | func TestSetFileIndex(t *testing.T) {
  function TestFileOutputAppendQueueLimitOverflow (line 203) | func TestFileOutputAppendQueueLimitOverflow(t *testing.T) {
  function TestFileOutputAppendQueueLimitNoOverflow (line 232) | func TestFileOutputAppendQueueLimitNoOverflow(t *testing.T) {
  function TestFileOutputAppendQueueLimitGzips (line 261) | func TestFileOutputAppendQueueLimitGzips(t *testing.T) {
  function TestFileOutputSort (line 290) | func TestFileOutputSort(t *testing.T) {
  function TestFileOutputAppendSizeLimitOverflow (line 300) | func TestFileOutputAppendSizeLimitOverflow(t *testing.T) {

FILE: output_http.go
  constant initialDynamicWorkers (line 20) | initialDynamicWorkers = 10
  constant readChunkSize (line 21) | readChunkSize         = 64 * 1024
  constant maxResponseSize (line 22) | maxResponseSize       = 1073741824
  type response (line 25) | type response struct
  type HTTPOutputConfig (line 33) | type HTTPOutputConfig struct
    method Copy (line 54) | func (hoc *HTTPOutputConfig) Copy() *HTTPOutputConfig {
  type HTTPOutput (line 78) | type HTTPOutput struct
    method workerMaster (line 198) | func (o *HTTPOutput) workerMaster() {
    method sessionWorkerMaster (line 225) | func (o *HTTPOutput) sessionWorkerMaster() {
    method startWorker (line 257) | func (o *HTTPOutput) startWorker() {
    method PluginWrite (line 269) | func (o *HTTPOutput) PluginWrite(msg *Message) (n int, err error) {
    method PluginRead (line 306) | func (o *HTTPOutput) PluginRead() (*Message, error) {
    method sendRequest (line 324) | func (o *HTTPOutput) sendRequest(client *HTTPClient, msg *Message) {
    method String (line 351) | func (o *HTTPOutput) String() string {
    method Close (line 356) | func (o *HTTPOutput) Close() error {
  type httpWorker (line 91) | type httpWorker struct
  function newHTTPWorker (line 99) | func newHTTPWorker(output *HTTPOutput, queue chan *Message) *httpWorker {
  function NewHTTPOutput (line 126) | func NewHTTPOutput(address string, config *HTTPOutputConfig) PluginReadW...
  type HTTPClient (line 363) | type HTTPClient struct
    method Send (line 397) | func (c *HTTPClient) Send(data []byte) ([]byte, error) {
  function NewHTTPClient (line 369) | func NewHTTPClient(config *HTTPOutputConfig) *HTTPClient {

FILE: output_http_test.go
  function TestHTTPOutput (line 12) | func TestHTTPOutput(t *testing.T) {
  function TestHTTPOutputKeepOriginalHost (line 71) | func TestHTTPOutputKeepOriginalHost(t *testing.T) {
  function TestHTTPOutputSSL (line 107) | func TestHTTPOutputSSL(t *testing.T) {
  function TestHTTPOutputSessions (line 136) | func TestHTTPOutputSessions(t *testing.T) {
  function BenchmarkHTTPOutput (line 182) | func BenchmarkHTTPOutput(b *testing.B) {
  function BenchmarkHTTPOutputTLS (line 211) | func BenchmarkHTTPOutputTLS(b *testing.B) {

FILE: output_kafka.go
  type KafkaOutput (line 16) | type KafkaOutput struct
    method ErrorHandler (line 58) | func (o *KafkaOutput) ErrorHandler() {
    method PluginWrite (line 65) | func (o *KafkaOutput) PluginWrite(msg *Message) (n int, err error) {
  constant KafkaOutputFrequency (line 22) | KafkaOutputFrequency = 500
  function NewKafkaOutput (line 25) | func NewKafkaOutput(_ string, config *OutputKafkaConfig, tlsConfig *Kafk...

FILE: output_kafka_test.go
  function TestOutputKafkaRAW (line 10) | func TestOutputKafkaRAW(t *testing.T) {
  function TestOutputKafkaJSON (line 33) | func TestOutputKafkaJSON(t *testing.T) {

FILE: output_null.go
  type NullOutput (line 4) | type NullOutput struct
    method PluginWrite (line 13) | func (o *NullOutput) PluginWrite(msg *Message) (int, error) {
    method String (line 17) | func (o *NullOutput) String() string {
  function NewNullOutput (line 8) | func NewNullOutput() (o *NullOutput) {

FILE: output_s3.go
  type S3Output (line 11) | type S3Output struct
    method PluginWrite (line 19) | func (o *S3Output) PluginWrite(msg *Message) (n int, err error) {
    method String (line 23) | func (o *S3Output) String() string {
    method Close (line 27) | func (o *S3Output) Close() error {
  function NewS3Output (line 14) | func NewS3Output(pathTemplate string, config *FileOutputConfig) *S3Output {

FILE: output_s3_pro.go
  type S3Output (line 24) | type S3Output struct
    method connect (line 62) | func (o *S3Output) connect() {
    method PluginWrite (line 69) | func (o *S3Output) PluginWrite(msg *Message) (n int, err error) {
    method String (line 73) | func (o *S3Output) String() string {
    method Close (line 77) | func (o *S3Output) Close() error {
    method keyPath (line 81) | func (o *S3Output) keyPath(idx int) (bucket, key string) {
    method onBufferUpdate (line 93) | func (o *S3Output) onBufferUpdate(path string) {
  function NewS3Output (line 34) | func NewS3Output(pathTemplate string, config *FileOutputConfig) *S3Output {

FILE: output_tcp.go
  type TCPOutput (line 15) | type TCPOutput struct
    method worker (line 59) | func (o *TCPOutput) worker(bufferIndex int) {
    method writeToConnection (line 101) | func (o *TCPOutput) writeToConnection(conn net.Conn, msg *Message) (er...
    method getBufferIndex (line 117) | func (o *TCPOutput) getBufferIndex(msg *Message) int {
    method PluginWrite (line 129) | func (o *TCPOutput) PluginWrite(msg *Message) (n int, err error) {
    method connect (line 144) | func (o *TCPOutput) connect(address string) (conn net.Conn, err error) {
    method String (line 161) | func (o *TCPOutput) String() string {
    method Close (line 165) | func (o *TCPOutput) Close() {
  type TCPOutputConfig (line 27) | type TCPOutputConfig struct
  function NewTCPOutput (line 39) | func NewTCPOutput(address string, config *TCPOutputConfig) PluginWriter {

FILE: output_tcp_test.go
  function TestTCPOutput (line 15) | func TestTCPOutput(t *testing.T) {
  function startTCP (line 25) | func startTCP(cb func([]byte)) net.Listener {
  function BenchmarkTCPOutput (line 52) | func BenchmarkTCPOutput(b *testing.B) {
  function TestStickyDisable (line 80) | func TestStickyDisable(t *testing.T) {
  function TestBufferDistribution (line 91) | func TestBufferDistribution(t *testing.T) {
  function getTestBytes (line 115) | func getTestBytes() *Message {
  function TestTCPOutputGetInitMessage (line 122) | func TestTCPOutputGetInitMessage(t *testing.T) {
  function TestTCPOutputGetInitMessageAndWriteBeforeMessage (line 145) | func TestTCPOutputGetInitMessageAndWriteBeforeMessage(t *testing.T) {
  function runTCPOutput (line 173) | func runTCPOutput(wg *sync.WaitGroup, output PluginWriter, repeat int, i...

FILE: output_ws.go
  type WebSocketOutput (line 20) | type WebSocketOutput struct
    method worker (line 78) | func (o *WebSocketOutput) worker(bufferIndex int) {
    method getBufferIndex (line 115) | func (o *WebSocketOutput) getBufferIndex(msg *Message) int {
    method PluginWrite (line 127) | func (o *WebSocketOutput) PluginWrite(msg *Message) (n int, err error) {
    method connect (line 142) | func (o *WebSocketOutput) connect(address string) (conn *websocket.Con...
    method String (line 155) | func (o *WebSocketOutput) String() string {
    method Close (line 160) | func (o *WebSocketOutput) Close() {
  type WebSocketOutputConfig (line 33) | type WebSocketOutputConfig struct
  function NewWebSocketOutput (line 43) | func NewWebSocketOutput(address string, config *WebSocketOutputConfig) P...

FILE: output_ws_test.go
  function TestWebSocketOutput (line 13) | func TestWebSocketOutput(t *testing.T) {
  function startWebsocket (line 54) | func startWebsocket(cb func([]byte), headercb func(http.Header)) string {

FILE: plugins.go
  type Message (line 9) | type Message struct
  type PluginReader (line 15) | type PluginReader interface
  type PluginWriter (line 20) | type PluginWriter interface
  type PluginReadWriter (line 25) | type PluginReadWriter interface
  type InOutPlugins (line 31) | type InOutPlugins struct
    method registerPlugin (line 52) | func (plugins *InOutPlugins) registerPlugin(constructor interface{}, o...
  function extractLimitOptions (line 39) | func extractLimitOptions(options string) (string, string) {
  function NewPlugins (line 89) | func NewPlugins() *InOutPlugins {

FILE: plugins_test.go
  function TestPluginsRegistration (line 7) | func TestPluginsRegistration(t *testing.T) {

FILE: proto/fuzz.go
  function Fuzz (line 5) | func Fuzz(data []byte) int {

FILE: proto/proto.go
  function MIMEHeadersEndPos (line 40) | func MIMEHeadersEndPos(payload []byte) int {
  function MIMEHeadersStartPos (line 50) | func MIMEHeadersStartPos(payload []byte) int {
  function header (line 61) | func header(payload []byte, name []byte) (value []byte, headerStart, hea...
  function ParseHeaders (line 124) | func ParseHeaders(p []byte) textproto.MIMEHeader {
  function GetHeaders (line 141) | func GetHeaders(p []byte) textproto.MIMEHeader {
  function Header (line 151) | func Header(payload, name []byte) []byte {
  function SetHeader (line 159) | func SetHeader(payload, name, value []byte) []byte {
  function AddHeader (line 172) | func AddHeader(payload, name, value []byte) []byte {
  function DeleteHeader (line 188) | func DeleteHeader(payload, name []byte) []byte {
  function Body (line 197) | func Body(payload []byte) []byte {
  function Path (line 206) | func Path(payload []byte) []byte {
  function SetPath (line 217) | func SetPath(payload, path []byte) []byte {
  function PathParam (line 228) | func PathParam(payload, name []byte) (value []byte, valueStart, valueEnd...
  function SetPathParam (line 253) | func SetPathParam(payload, name, value []byte) []byte {
  function SetHost (line 290) | func SetHost(payload, url, host []byte) []byte {
  function Method (line 309) | func Method(payload []byte) []byte {
  function Status (line 320) | func Status(payload []byte) []byte {
  constant MinRequestCount (line 338) | MinRequestCount = 16
  constant MinResponseCount (line 340) | MinResponseCount = 14
  constant VersionLen (line 342) | VersionLen = 8
  function HasResponseTitle (line 346) | func HasResponseTitle(payload []byte) bool {
  function HasRequestTitle (line 375) | func HasRequestTitle(payload []byte) bool {
  function HasTitle (line 406) | func HasTitle(payload []byte) bool {
  function CheckChunked (line 413) | func CheckChunked(bufs ...[]byte) (chunkEnd int, full bool) {
  type ProtocolStateSetter (line 449) | type ProtocolStateSetter interface
  type HTTPState (line 454) | type HTTPState struct
  function HasFullPayload (line 469) | func HasFullPayload(m ProtocolStateSetter, payloads ...[]byte) bool {
  function atoI (line 581) | func atoI(s []byte, base int) (num int, ok bool) {

FILE: proto/proto_test.go
  function TestHeader (line 10) | func TestHeader(t *testing.T) {
  function TestMIMEHeadersEndPos (line 67) | func TestMIMEHeadersEndPos(t *testing.T) {
  function TestMIMEHeadersStartPos (line 78) | func TestMIMEHeadersStartPos(t *testing.T) {
  function TestSetHeader (line 90) | func TestSetHeader(t *testing.T) {
  function TestDeleteHeader (line 112) | func TestDeleteHeader(t *testing.T) {
  function TestParseHeaders (line 131) | func TestParseHeaders(t *testing.T) {
  function TestFuzzCrashers (line 166) | func TestFuzzCrashers(t *testing.T) {
  function TestParseHeadersWithComplexUserAgent (line 176) | func TestParseHeadersWithComplexUserAgent(t *testing.T) {
  function TestParseHeadersWithOrigin (line 192) | func TestParseHeadersWithOrigin(t *testing.T) {
  function TestPath (line 218) | func TestPath(t *testing.T) {
  function TestStatus (line 246) | func TestStatus(t *testing.T) {
  function TestSetPath (line 265) | func TestSetPath(t *testing.T) {
  function TestPathParam (line 277) | func TestPathParam(t *testing.T) {
  function TestSetPathParam (line 300) | func TestSetPathParam(t *testing.T) {
  function TestSetHostHTTP10 (line 332) | func TestSetHostHTTP10(t *testing.T) {
  function TestHasResponseTitle (line 356) | func TestHasResponseTitle(t *testing.T) {
  function TestHasRequestTitle (line 377) | func TestHasRequestTitle(t *testing.T) {
  function TestCheckChunks (line 395) | func TestCheckChunks(t *testing.T) {
  function TestHasFullPayload (line 435) | func TestHasFullPayload(t *testing.T) {
  function BenchmarkHasFullPayload (line 498) | func BenchmarkHasFullPayload(b *testing.B) {

FILE: protocol.go
  constant RequestPayload (line 12) | RequestPayload          = '1'
  constant ResponsePayload (line 13) | ResponsePayload         = '2'
  constant ReplayedResponsePayload (line 14) | ReplayedResponsePayload = '3'
  function randByte (line 17) | func randByte(len int) []byte {
  function uuid (line 27) | func uuid() []byte {
  function payloadScanner (line 33) | func payloadScanner(data []byte, atEOF bool) (advance int, token []byte,...
  function payloadHeader (line 50) | func payloadHeader(payloadType byte, uuid []byte, timing int64, latency ...
  function payloadBody (line 56) | func payloadBody(payload []byte) []byte {
  function payloadMeta (line 61) | func payloadMeta(payload []byte) [][]byte {
  function payloadMetaWithBody (line 69) | func payloadMetaWithBody(payload []byte) (meta, body []byte) {
  function payloadID (line 79) | func payloadID(payload []byte) (id []byte) {
  function isOriginPayload (line 88) | func isOriginPayload(payload []byte) bool {
  function isRequestPayload (line 92) | func isRequestPayload(payload []byte) bool {

FILE: s3_reader.go
  type S3ReadCloser (line 16) | type S3ReadCloser struct
    method Read (line 74) | func (s *S3ReadCloser) Read(b []byte) (n int, e error) {
    method Close (line 103) | func (s *S3ReadCloser) Close() error {
  function awsConfig (line 26) | func awsConfig() *aws.Config {
  function NewS3ReadCloser (line 54) | func NewS3ReadCloser(path string) *S3ReadCloser {

FILE: s3_test.go
  function TestS3Output (line 17) | func TestS3Output(t *testing.T) {
  function TestS3OutputQueueLimit (line 61) | func TestS3OutputQueueLimit(t *testing.T) {
  function TestInputFileFromS3 (line 109) | func TestInputFileFromS3(t *testing.T) {

FILE: settings.go
  type MultiOption (line 18) | type MultiOption struct
    method String (line 22) | func (h *MultiOption) String() string {
    method Set (line 30) | func (h *MultiOption) Set(value string) error {
  type MultiIntOption (line 40) | type MultiIntOption struct
    method String (line 44) | func (h *MultiIntOption) String() string {
    method Set (line 53) | func (h *MultiIntOption) Set(value string) error {
  type AppSettings (line 64) | type AppSettings struct
  function usage (line 122) | func usage() {
  function init (line 128) | func init() {
  function CheckSettings (line 280) | func CheckSettings() {
  function Debug (line 298) | func Debug(level int, args ...interface{}) {

FILE: settings_test.go
  function TestAppSettings (line 8) | func TestAppSettings(t *testing.T) {

FILE: tcp_client.go
  type TCPClientConfig (line 13) | type TCPClientConfig struct
  type TCPClient (line 22) | type TCPClient struct
    method Connect (line 50) | func (c *TCPClient) Connect() (err error) {
    method Disconnect (line 69) | func (c *TCPClient) Disconnect() {
    method isAlive (line 77) | func (c *TCPClient) isAlive() bool {
    method Send (line 98) | func (c *TCPClient) Send(data []byte) (response []byte, err error) {
  function NewTCPClient (line 32) | func NewTCPClient(addr string, config *TCPClientConfig) *TCPClient {

FILE: test_input.go
  type TestInput (line 14) | type TestInput struct
    method PluginRead (line 29) | func (i *TestInput) PluginRead() (*Message, error) {
    method Close (line 47) | func (i *TestInput) Close() error {
    method EmitBytes (line 53) | func (i *TestInput) EmitBytes(data []byte) {
    method EmitGET (line 58) | func (i *TestInput) EmitGET() {
    method EmitPOST (line 63) | func (i *TestInput) EmitPOST() {
    method EmitChunkedPOST (line 68) | func (i *TestInput) EmitChunkedPOST() {
    method EmitLargePOST (line 73) | func (i *TestInput) EmitLargePOST() {
    method EmitSizedPOST (line 84) | func (i *TestInput) EmitSizedPOST(payloadSize int) {
    method EmitOPTIONS (line 94) | func (i *TestInput) EmitOPTIONS() {
    method String (line 98) | func (i *TestInput) String() string {
  function NewTestInput (line 21) | func NewTestInput() (i *TestInput) {

FILE: test_output.go
  type writeCallback (line 3) | type writeCallback
  type TestOutput (line 6) | type TestOutput struct
    method PluginWrite (line 19) | func (i *TestOutput) PluginWrite(msg *Message) (int, error) {
    method String (line 25) | func (i *TestOutput) String() string {
  function NewTestOutput (line 11) | func NewTestOutput(cb writeCallback) PluginWriter {
Condensed preview — 162 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (722K chars).
[
  {
    "path": ".clabot",
    "chars": 32,
    "preview": "{\n  \"contributors\": [\"buger\"]\n}\n"
  },
  {
    "path": ".deepsource.toml",
    "chars": 353,
    "preview": "version = 1\n\nexclude_patterns = [\n  \"vendor/**\"\n]\n\n[[analyzers]]\nname = \"go\"\nenabled = true\n\n  [analyzers.meta]\n  import"
  },
  {
    "path": ".dockerignore",
    "chars": 22,
    "preview": "*.tar.gz\ngor\ngor.test\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "chars": 467,
    "preview": "version: 2\nupdates:\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: "
  },
  {
    "path": ".github/workflows/ci-docker.yaml",
    "chars": 1162,
    "preview": "name: ci\non:\n  release:\n    types: [published]\njobs:\n  docker-build-and-push:\n    runs-on: ubuntu-latest\n    steps:\n    "
  },
  {
    "path": ".github/workflows/ci-test.yaml",
    "chars": 851,
    "preview": "name: test\non: [push, pull_request]\njobs:\n  test:\n    strategy:\n      matrix:\n        go-version: [1.18.x, 1.19.x] # two"
  },
  {
    "path": ".github/workflows/codesee-arch-diagram.yml",
    "chars": 549,
    "preview": "# This workflow was added by CodeSee. Learn more at https://codesee.io/\n# This is v2.0 of this workflow file\non:\n  push:"
  },
  {
    "path": ".github/workflows/probe.yaml",
    "chars": 1510,
    "preview": "name: AI Comment Handler\n\n\non:\n  pull_request:\n    types: [opened] #[opened , labeled]\n  issue_comment:\n    types: [crea"
  },
  {
    "path": ".github/workflows/semgrep.yml",
    "chars": 469,
    "preview": "on:\n  pull_request: {}\n  push:\n    branches:\n    - main\n    - master\n    paths:\n    - .github/workflows/semgrep.yml\n  sc"
  },
  {
    "path": ".gitignore",
    "chars": 211,
    "preview": "vendor\n*.swp\n*.gor\n*.rpm\n*.dep\n*.deb\n*.pkg\n*.exe\n*.pprof\n*.out\nhey\n\n*.bin\nlib/\noutput/\n*.gz\n*.zip\n.aider*\n\n*.class\n\n*.te"
  },
  {
    "path": ".gitmodules",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".request",
    "chars": 64,
    "preview": "POST /post HTTP/1.1\nContent-Length: 7\nHost: www.w3.org\n\na=1&b=2\n"
  },
  {
    "path": "COMM-LICENSE",
    "chars": 18180,
    "preview": "END-USER LICENSE AGREEMENT\n\n------------------------------------------------------------------------------\n\nIMPORTANT: T"
  },
  {
    "path": "Dockerfile",
    "chars": 381,
    "preview": "FROM alpine:3.16 as builder\n\nARG RELEASE_VERSION\n\nRUN apk add --no-cache ca-certificates openssl\nRUN wget https://github"
  },
  {
    "path": "Dockerfile.dev",
    "chars": 434,
    "preview": "ARG BASE_IMAGE\nFROM ${BASE_IMAGE}\n\nRUN apk add --no-cache \\\n    gcc \\\n    g++ \\\n    make \\\n    linux-headers \\\n    bison"
  },
  {
    "path": "ELASTICSEARCH.md",
    "chars": 1961,
    "preview": "gor & elasticsearch\n===================\n\nPrerequisites\n-------------\n\n- elasticsearch\n- kibana (Get it here: http://www."
  },
  {
    "path": "LICENSE.txt",
    "chars": 1568,
    "preview": "Copyright (c) 2011-present Leonid Bugaev\n\nPortions of this software are licensed as follows:\n\n* All content residing und"
  },
  {
    "path": "Makefile",
    "chars": 6539,
    "preview": "SOURCE = $(shell ls -1 *.go | grep -v _test.go)\nPROJECT_NAME := goreplay\nSOURCE_PATH = /go/src/github.com/buger/goreplay"
  },
  {
    "path": "Procfile",
    "chars": 253,
    "preview": "web: python -m SimpleHTTPServer 8000\nreplayed_web: python -m SimpleHTTPServer 8001\nlistener: sudo -E go run ./bin/gor.go"
  },
  {
    "path": "README.md",
    "chars": 5136,
    "preview": "<a href=\"https://semgrep.dev/login?utm_source=github&utm_medium=badge&utm_campaign=growth-oss\"><img src=\"https://img.shi"
  },
  {
    "path": "ce.go",
    "chars": 364,
    "preview": "//go:build !pro\n\npackage goreplay\n\nimport (\n\t\"fmt\"\n)\n\n// PRO this value indicates if goreplay is running in PRO mode.\nva"
  },
  {
    "path": "circle.yml",
    "chars": 280,
    "preview": "dependencies:\n  pre:\n    - sudo apt-get install libpcap-dev -y\n\ntest:\n  override:\n    - sudo bash -l -c \"export GOPATH='"
  },
  {
    "path": "docs/CNAME",
    "chars": 17,
    "preview": "docs.goreplay.org"
  },
  {
    "path": "docs/Capturing-and-replaying-traffic.md",
    "chars": 2598,
    "preview": "Think about Gor more like a network analyzer or tcpdump on steroids, it is not a proxy and does not affect your app anyh"
  },
  {
    "path": "docs/Compilation.md",
    "chars": 1389,
    "preview": "We provide pre-compiled binaries for Mac and Linux, but you are free to compile Gor by yourself.\n\nGor is written using G"
  },
  {
    "path": "docs/Development-Setup.md",
    "chars": 855,
    "preview": "## STEP 1: Install Docker\nFor local development we recommend to use Docker.\n\nIf you don’t have it you can read how to in"
  },
  {
    "path": "docs/Distributed-configuration.md",
    "chars": 1837,
    "preview": "Sometimes it makes sense to use separate Gor instance for replaying traffic and performing things like load testing, so "
  },
  {
    "path": "docs/Exporting-to-ElasticSearch.md",
    "chars": 1665,
    "preview": "Gor can export requests and replayed response data to ElasticSearch:\n\n```\n./gor --input-raw :8000 --output-http http://s"
  },
  {
    "path": "docs/FAQ.md",
    "chars": 2601,
    "preview": "### What OS are supported?\nGor will run everywhere where [libpcap](http://www.tcpdump.org/) works, and it works on most "
  },
  {
    "path": "docs/Middleware.md",
    "chars": 4646,
    "preview": "#### Overview\nMiddleware is a program that accepts request and response payload at STDIN and emits modified requests at "
  },
  {
    "path": "docs/Rate-limiting.md",
    "chars": 1867,
    "preview": "Rate limiting can be useful if you only want to forward parts of incoming traffic, for example, to not overload your tes"
  },
  {
    "path": "docs/Replaying-HTTP-traffic.md",
    "chars": 2441,
    "preview": "Gor can replay HTTP traffic using `--output-http` option:\n\n```bash\nsudo ./gor --input-raw :8000 --output-http=\"http://st"
  },
  {
    "path": "docs/Request-filtering.md",
    "chars": 1221,
    "preview": "Filtering is useful when you need to capture only specific part of traffic, like API requests. It is possible to filter "
  },
  {
    "path": "docs/Request-rewriting.md",
    "chars": 1979,
    "preview": "Gor supports rewriting of URLs, URL params and headers, see below.\n\nRewriting may be useful if you test environment does"
  },
  {
    "path": "docs/Running-as-non-root-user.md",
    "chars": 883,
    "preview": "You can enable Gor for non-root users in a secure method by using the following commands\n\n``` \n# Following commands assu"
  },
  {
    "path": "docs/Saving-and-Replaying-from-file.md",
    "chars": 4865,
    "preview": "You can save requests to file, and replay them later. While replaying it will preserve the original time differences bet"
  },
  {
    "path": "docs/Troubleshooting.md",
    "chars": 4690,
    "preview": "Gor can report stats on the `output-tcp` and `output-http` request queues. Stats are reported to the console every 5 sec"
  },
  {
    "path": "docs/_Footer.md",
    "chars": 186,
    "preview": "[Website](https://goreplay.org) | [PRO version](https://goreplay.org/pro.html) | [[Getting started]] | [[FAQ]] | [Join n"
  },
  {
    "path": "docs/_config.yml",
    "chars": 26,
    "preview": "theme: jekyll-theme-cayman"
  },
  {
    "path": "docs/commercial/collaboration.md",
    "chars": 1022,
    "preview": "Collaboration is difficult with commercial closed source but I do want to keep as much of the OSS ethos as possible avai"
  },
  {
    "path": "docs/commercial/faq.md",
    "chars": 4285,
    "preview": "### What are GoReplay PRO and GoReplay Enterprise?\n\n[GoReplay PRO](https://goreplay.org/pro.html) and GoReplay Enterpris"
  },
  {
    "path": "docs/commercial/support.md",
    "chars": 812,
    "preview": "Gor offers only community support.  Gor Pro and Enterprise offer priority support via email.\n\n## Priority Support\n\nCover"
  },
  {
    "path": "docs/css/breadcrumbs.css",
    "chars": 584,
    "preview": ".wy-breadcrumbs li {\n  display: inline-block;\n}\n\n.wy-breadcrumbs li.wy-breadcrumbs-aside {\n  float: right;\n}\n\n.wy-breadc"
  },
  {
    "path": "docs/css/code.css",
    "chars": 3956,
    "preview": ".codeblock-example {\n  border: 1px solid #e1e4e5;\n  border-bottom: none;\n  padding: 24px;\n  padding-top: 48px;\n  font-we"
  },
  {
    "path": "docs/css/fabric.css",
    "chars": 78220,
    "preview": "/* Taken from https://docs.fabric.io/apple/fabric/overview.html */\n\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-siz"
  },
  {
    "path": "docs/css/goreplay.css",
    "chars": 3488,
    "preview": "code {\n  font-family: Consolas, \"Liberation Mono\", Menlo, Courier, monospace !important;\n  border-bottom-left-radius: 3p"
  },
  {
    "path": "docs/css/sidenav.css",
    "chars": 8630,
    "preview": ".wy-affix {\n  position: fixed;\n  top: 1.618em;\n}\n\n.wy-menu a:hover {\n  text-decoration: none;\n}\n\n.wy-menu-vertical heade"
  },
  {
    "path": "docs/getting-started/basics.md",
    "chars": 1405,
    "preview": "### Overview\nGor architecture tries to follow UNIX philosophy: everything made of pipes, various inputs multiplexing dat"
  },
  {
    "path": "docs/getting-started/tutorial.md",
    "chars": 2889,
    "preview": "### Dependencies\nTo start working with Gor, you need to have a web server running on your machine, and a terminal to run"
  },
  {
    "path": "docs/index.md",
    "chars": 964,
    "preview": "Gor is an open-source tool for capturing and replaying live HTTP traffic into a test environment in order to continuousl"
  },
  {
    "path": "docs/js/base.js",
    "chars": 387,
    "preview": "$(document).ready(function () {\n    $('img[alt=\"YOUTUBE\"]').each(function () {\n        var id = $(this).attr('src').spli"
  },
  {
    "path": "docs/js/turbolinks.js",
    "chars": 34673,
    "preview": "/*\nTurbolinks 5.0.0\nCopyright © 2016 Basecamp, LLC\n */\n(function(){(function(){(function(){this.Turbolinks={supported:fu"
  },
  {
    "path": "docs/pro/recording-and-replaying-keep-alive-tcp-sessions.md",
    "chars": 1021,
    "preview": "> **This feature available only in PRO version. See https://goreplay.org/pro.html for details.**\n\nBy default, GoReplay d"
  },
  {
    "path": "docs/pro/replaying-binary-protocols.md",
    "chars": 1187,
    "preview": "> **This feature available only in PRO version. See https://goreplay.org/pro.html for details.**\n\nGor includes basic sup"
  },
  {
    "path": "elasticsearch.go",
    "chars": 5278,
    "preview": "package goreplay\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"log\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n\n\tel"
  },
  {
    "path": "elasticsearch_test.go",
    "chars": 3499,
    "preview": "package goreplay\n\nimport (\n\t\"testing\"\n)\n\nconst expectedIndex = \"gor\"\n\nfunc assertExpectedGorIndex(index string, t *testi"
  },
  {
    "path": "emitter.go",
    "chars": 3908,
    "preview": "package goreplay\n\nimport (\n\t\"fmt\"\n\t\"github.com/buger/goreplay/internal/byteutils\"\n\t\"hash/fnv\"\n\t\"io\"\n\t\"log\"\n\t\"sync\"\n\n\t\"gi"
  },
  {
    "path": "emitter_test.go",
    "chars": 5330,
    "preview": "package goreplay\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestMain(m *testing.M) {\n\tPRO "
  },
  {
    "path": "examples/middleware/echo.clj",
    "chars": 1577,
    "preview": "(ns echo.core\n  (:gen-class)\n  (:require [clojure.string :as cs]\n            [clojure.java.io :as io])\n  (:import org.ap"
  },
  {
    "path": "examples/middleware/echo.java",
    "chars": 1371,
    "preview": "import java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\n\nimport org.apache.commons."
  },
  {
    "path": "examples/middleware/echo.js",
    "chars": 1272,
    "preview": "#!/usr/bin/env node\nconst readline = require(\"readline\");\nconst StringDecoder = require(\"string_decoder\").StringDecoder\n"
  },
  {
    "path": "examples/middleware/echo.py",
    "chars": 1915,
    "preview": "#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\n\nimport sys\nimport fileinput\nimport binascii\n\n# Used to find end of the "
  },
  {
    "path": "examples/middleware/echo.rb",
    "chars": 551,
    "preview": "#!/usr/bin/env ruby\n# encoding: utf-8\nwhile data = STDIN.gets # continuously read line from STDIN\n  next unless data\n  d"
  },
  {
    "path": "examples/middleware/echo.sh",
    "chars": 1174,
    "preview": "#!/usr/bin/env bash\n#\n# `xxd` utility included into vim-common package\n# It allow hex decoding/encoding\n# \n# This exampl"
  },
  {
    "path": "examples/middleware/token_modifier.go",
    "chars": 3964,
    "preview": "/*\nThis middleware made for auth system that randomly generate access tokens, which used later for accessing secure cont"
  },
  {
    "path": "go.mod",
    "chars": 3512,
    "preview": "module github.com/buger/goreplay\n\ngo 1.21\n\nrequire (\n\tgithub.com/Shopify/sarama v1.38.1\n\tgithub.com/aws/aws-sdk-go v1.44"
  },
  {
    "path": "go.sum",
    "chars": 36410,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
  },
  {
    "path": "gor_stat.go",
    "chars": 1191,
    "preview": "package goreplay\n\nimport (\n\t\"runtime\"\n\t\"strconv\"\n\t\"time\"\n)\n\ntype GorStat struct {\n\tstatName string\n\trateMs   int\n\tlatest"
  },
  {
    "path": "homebrew/gor.rb",
    "chars": 1549,
    "preview": "require \"language/go\"\n\nclass Gor < Formula\n  desc \"Real-time HTTP traffic replay tool written in Go\"\n  homepage \"https:/"
  },
  {
    "path": "http_modifier.go",
    "chars": 3970,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"hash/fnv\"\n\t\"strings\"\n)\n\ntype"
  },
  {
    "path": "http_modifier_settings.go",
    "chars": 7054,
    "preview": "package goreplay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// HTTPModifierConfig holds configuration"
  },
  {
    "path": "http_modifier_settings_test.go",
    "chars": 1281,
    "preview": "package goreplay\n\nimport (\n\t\"testing\"\n)\n\nfunc TestHTTPHeaderFilters(t *testing.T) {\n\tfilters := HTTPHeaderFilters{}\n\n\ter"
  },
  {
    "path": "http_modifier_test.go",
    "chars": 9129,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"testing\"\n)\n\nfunc TestHTTPModifierWithoutConfig("
  },
  {
    "path": "http_prettifier.go",
    "chars": 1407,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"fmt\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"io/ioutil\"\n\t\"net/http/h"
  },
  {
    "path": "http_prettifier_test.go",
    "chars": 983,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"strconv\"\n\t\"testing\"\n)\n\nfunc Te"
  },
  {
    "path": "input_dummy.go",
    "chars": 1302,
    "preview": "package goreplay\n\nimport (\n\t\"time\"\n)\n\n// DummyInput used for debugging. It generate 1 \"GET /\"\" request per second.\ntype "
  },
  {
    "path": "input_file.go",
    "chars": 8749,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"container/heap\"\n\t\"errors\"\n\t\"expvar\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\""
  },
  {
    "path": "input_file_test.go",
    "chars": 9505,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"math/rand\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc "
  },
  {
    "path": "input_http.go",
    "chars": 1702,
    "preview": "package goreplay\n\nimport (\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"time\"\n)\n\n// HTTPInput used for sending reque"
  },
  {
    "path": "input_http_test.go",
    "chars": 1628,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestHTTPInput(t *testing.T"
  },
  {
    "path": "input_kafka.go",
    "chars": 4175,
    "preview": "package goreplay\n\nimport (\n\t\"encoding/json\"\n\t\"log\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/Shopify/sarama\"\n\t\"github."
  },
  {
    "path": "input_kafka_test.go",
    "chars": 1483,
    "preview": "package goreplay\n\nimport (\n\t\"testing\"\n\n\t\"github.com/Shopify/sarama\"\n\t\"github.com/Shopify/sarama/mocks\"\n)\n\nfunc TestInput"
  },
  {
    "path": "input_raw.go",
    "chars": 4041,
    "preview": "package goreplay\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/buger/goreplay/internal/capture\"\n\t\"github.com/buger/goreplay/i"
  },
  {
    "path": "input_raw_test.go",
    "chars": 8290,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"github.com/buger/goreplay/internal/capture\"\n\t\"github.com/buger/goreplay/internal/t"
  },
  {
    "path": "input_tcp.go",
    "chars": 3206,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n)\n\n// TCPInput used for internal c"
  },
  {
    "path": "input_tcp_test.go",
    "chars": 3205,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"encoding/pem\"\n\t\"io/iouti"
  },
  {
    "path": "internal/byteutils/byteutils.go",
    "chars": 1107,
    "preview": "// Package byteutils provides helpers for working with byte slices\npackage byteutils\n\nimport (\n\t\"unsafe\"\n)\n\n// Cut eleme"
  },
  {
    "path": "internal/byteutils/byteutils_test.go",
    "chars": 1012,
    "preview": "package byteutils\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestCut(t *testing.T) {\n\tif !bytes.Equal(Cut([]byte(\"123456\"), 2"
  },
  {
    "path": "internal/capture/af_packet.go",
    "chars": 927,
    "preview": "//go:build !linux\n\npackage capture\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/google/gopacket\"\n)\n\nfunc newAfpacketHandle(dev"
  },
  {
    "path": "internal/capture/af_packet_linux.go",
    "chars": 3168,
    "preview": "//go:build linux\n\npackage capture\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/a"
  },
  {
    "path": "internal/capture/capture.go",
    "chars": 22338,
    "preview": "package capture\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"expvar\"\n\t\"fmt\"\n\t\"github.com/buger/goreplay/internal/size\"\n\t\"github.com/"
  },
  {
    "path": "internal/capture/capture_test.go",
    "chars": 385,
    "preview": "package capture\n\nimport (\n\t\"testing\"\n)\n\nfunc TestSetInterfaces(t *testing.T) {\n\tlistener := &Listener{\n\t\tloopIndex: 9999"
  },
  {
    "path": "internal/capture/doc.go",
    "chars": 1019,
    "preview": "/*\nPackage capture provides traffic sniffier using AF_PACKET, pcap or pcap file.\nit allows you to listen for traffic fro"
  },
  {
    "path": "internal/capture/dump.go",
    "chars": 4456,
    "preview": "// https://github.com/google/gopacket/blob/403ca653c4/pcapgo/read.go\n\npackage capture\n\nimport (\n\t\"encoding/binary\"\n\t\"fmt"
  },
  {
    "path": "internal/capture/sock_linux.go",
    "chars": 7280,
    "preview": "//go:build linux && !arm64\n\npackage capture\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/unix\"\n"
  },
  {
    "path": "internal/capture/sock_others.go",
    "chars": 299,
    "preview": "//go:build !linux || arm64 || darwin\n\npackage capture\n\nimport (\n\t\"errors\"\n\n\t\"github.com/google/gopacket/pcap\"\n)\n\n// NewS"
  },
  {
    "path": "internal/capture/socket.go",
    "chars": 417,
    "preview": "package capture\n\nimport (\n\t\"time\"\n\n\t\"github.com/google/gopacket\"\n)\n\n// Socket is any interface that defines the behavior"
  },
  {
    "path": "internal/capture/vxlan.go",
    "chars": 2068,
    "preview": "package capture\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/layers\"\n\t\"net\"\n\t\"t"
  },
  {
    "path": "internal/ring/ring.go",
    "chars": 5491,
    "preview": "package ring\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\t// ErrDisposed is returned when an operatio"
  },
  {
    "path": "internal/simpletime/time.go",
    "chars": 185,
    "preview": "package simpletime\n\nimport (\n\t\"time\"\n)\n\nvar Now time.Time\n\nfunc init() {\n\tgo func() {\n\t\tfor {\n\t\t\t// Accurate enough\n\t\t\tN"
  },
  {
    "path": "internal/size/size.go",
    "chars": 1350,
    "preview": "package size\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n)\n\n// Size represents size that implements flag.Var\ntype Size int64\n\n"
  },
  {
    "path": "internal/size/size_test.go",
    "chars": 717,
    "preview": "package size\n\nimport \"testing\"\n\nfunc TestParseDataUnit(t *testing.T) {\n\tvar d = map[string]int{\n\t\t\"42mb\":               "
  },
  {
    "path": "internal/tcp/doc.go",
    "chars": 1075,
    "preview": "/*\nPackage tcp implements TCP transport layer protocol, it is responsible for\nparsing, reassembling tcp packets, handlin"
  },
  {
    "path": "internal/tcp/tcp_message.go",
    "chars": 10419,
    "preview": "package tcp\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/buger/goreplay/proto\"\n\t\"net\"\n\t\"reflect\"\n\t\"s"
  },
  {
    "path": "internal/tcp/tcp_packet.go",
    "chars": 6235,
    "preview": "package tcp\n\nimport (\n\t\"encoding/binary\"\n\t\"expvar\"\n\t\"fmt\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/google/gopacket\"\n)\n\nfunc copySlic"
  },
  {
    "path": "internal/tcp/tcp_test.go",
    "chars": 11275,
    "preview": "package tcp\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"github.com/buger/goreplay/proto\"\n\n\t// \"runtime\"\n\t\"testing\"\n\t\"time\"\n\n"
  },
  {
    "path": "k8s/README.md",
    "chars": 4392,
    "preview": "# Native k8s integration\n\nAfter following steps below, you will be able to capture traffic inside k8s like this:\n\n```\ngo"
  },
  {
    "path": "k8s/clusterrole.yaml",
    "chars": 337,
    "preview": "kind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: pod-reader\nrules:\n- apiGroups: [\"\"]\n  resou"
  },
  {
    "path": "k8s/collect_goreplay_telemetry.sh",
    "chars": 4139,
    "preview": "#!/usr/bin/env bash\n#\n# collect_goreplay_telemetry.sh\n#\n# Gathers telemetry from a GoReplay DaemonSet in the 'goreplay' "
  },
  {
    "path": "k8s/goreplay.yaml",
    "chars": 448,
    "preview": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n  name: goreplay-daemon\nspec:\n  selector:\n    matchLabels:\n      app: gore"
  },
  {
    "path": "k8s/nginx.yaml",
    "chars": 504,
    "preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: nginx\n  labels:\n    app: nginx\nspec:\n  replicas: 1\n  selector:\n  "
  },
  {
    "path": "k8s/rolebinding.yaml",
    "chars": 243,
    "preview": "kind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n  name: goreplay-reader-binding\nsubjects:\n- "
  },
  {
    "path": "kafka.go",
    "chars": 5336,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"gi"
  },
  {
    "path": "limiter.go",
    "chars": 2783,
    "preview": "package goreplay\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Limiter is a wrapper for input "
  },
  {
    "path": "limiter_test.go",
    "chars": 2057,
    "preview": "//go:build !race\n\npackage goreplay\n\nimport (\n\t\"sync\"\n\t\"testing\"\n)\n\nfunc TestOutputLimiter(t *testing.T) {\n\twg := new(syn"
  },
  {
    "path": "middleware/README.md",
    "chars": 11179,
    "preview": "# GoReplay middleware\n\nGoReplay support protocol for writing middleware in any language, which allows you to implement c"
  },
  {
    "path": "middleware/middleware.js",
    "chars": 23601,
    "preview": "// ======= GoReplay Middleware helper =============\n// Created by Leonid Bugaev in 2017\n//\n// For questions use GitHub o"
  },
  {
    "path": "middleware/package.json",
    "chars": 491,
    "preview": "{\n  \"name\": \"goreplay_middleware\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Package for writing middleware for GoReplay h"
  },
  {
    "path": "middleware.go",
    "chars": 3419,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscal"
  },
  {
    "path": "middleware_test.go",
    "chars": 4907,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"testing\"\n)\n\nconst"
  },
  {
    "path": "mkdocs.yml",
    "chars": 38,
    "preview": "site_name: My Docs\ntheme: readthedocs\n"
  },
  {
    "path": "nfpm.yaml",
    "chars": 529,
    "preview": "# nfpm example config file\n#\n# check https://nfpm.goreleaser.com/configuration for detailed usage\n#\nname: \"GoReplay\"\narc"
  },
  {
    "path": "output_binary.go",
    "chars": 1611,
    "preview": "//go:build !pro\n\npackage goreplay\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/buger/goreplay/internal/size\"\n)\n\nvar _ Plugi"
  },
  {
    "path": "output_binary_pro.go",
    "chars": 4204,
    "preview": "//go:build pro\n\npackage goreplay\n\nimport (\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/buger/goreplay/internal/size\"\n)\n\nvar _ P"
  },
  {
    "path": "output_dummy.go",
    "chars": 617,
    "preview": "package goreplay\n\nimport (\n\t\"os\"\n)\n\n// DummyOutput used for debugging, prints all incoming requests\ntype DummyOutput str"
  },
  {
    "path": "output_file.go",
    "chars": 7124,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"compress/gzip\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/buger/goreplay/internal/size\"\n\t\"io\"\n\t"
  },
  {
    "path": "output_file_test.go",
    "chars": 9082,
    "preview": "package goreplay\n\nimport (\n\t\"fmt\"\n\t\"github.com/buger/goreplay/internal/size\"\n\t\"math/rand\"\n\t\"os\"\n\t\"reflect\"\n\t\"sort\"\n\t\"syn"
  },
  {
    "path": "output_http.go",
    "chars": 11191,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"net/http\"\n\t\"net/http/httputil\"\n\t\"net/"
  },
  {
    "path": "output_http_test.go",
    "chars": 5468,
    "preview": "package goreplay\n\nimport (\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t_ \"net/http/httputil\"\n\t\"sync\"\n\t\"testing\"\n)\n\nfu"
  },
  {
    "path": "output_kafka.go",
    "chars": 2678,
    "preview": "package goreplay\n\nimport (\n\t\"encoding/json\"\n\t\"github.com/buger/goreplay/internal/byteutils\"\n\t\"github.com/buger/goreplay/"
  },
  {
    "path": "output_kafka_test.go",
    "chars": 1369,
    "preview": "package goreplay\n\nimport (\n\t\"testing\"\n\n\t\"github.com/Shopify/sarama\"\n\t\"github.com/Shopify/sarama/mocks\"\n)\n\nfunc TestOutpu"
  },
  {
    "path": "output_null.go",
    "chars": 421,
    "preview": "package goreplay\n\n// NullOutput used for debugging, prints nothing\ntype NullOutput struct {\n}\n\n// NewNullOutput construc"
  },
  {
    "path": "output_s3.go",
    "chars": 658,
    "preview": "//go:build !pro\n\npackage goreplay\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// S3Output output plugin\ntype S3Output struct{}\n\n// New"
  },
  {
    "path": "output_s3_pro.go",
    "chars": 2385,
    "preview": "//go:build pro\n\npackage goreplay\n\nimport (\n\t_ \"bufio\"\n\t\"fmt\"\n\t_ \"io\"\n\t\"log\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"string"
  },
  {
    "path": "output_tcp.go",
    "chars": 3888,
    "preview": "package goreplay\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"net\"\n\t\"time\"\n)\n\n// TCPOutput used for sending r"
  },
  {
    "path": "output_tcp_test.go",
    "chars": 4713,
    "preview": "package goreplay\n\nimport (\n\t\"bufio\"\n\t\"log\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/a"
  },
  {
    "path": "output_ws.go",
    "chars": 3804,
    "preview": "package goreplay\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"log\"\n\t\"net/http\"\n\t\"net/url\"\n"
  },
  {
    "path": "output_ws_test.go",
    "chars": 1647,
    "preview": "package goreplay\n\nimport (\n\t\"log\"\n\t\"net/http\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/gorilla/websocket\"\n\t\"github.com/stretchr/"
  },
  {
    "path": "plugins.go",
    "chars": 4613,
    "preview": "package goreplay\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n)\n\n// Message represents data across plugins\ntype Message struct {\n\tMet"
  },
  {
    "path": "plugins_test.go",
    "chars": 1004,
    "preview": "package goreplay\n\nimport (\n\t\"testing\"\n)\n\nfunc TestPluginsRegistration(t *testing.T) {\n\tSettings.InputDummy = []string{\"["
  },
  {
    "path": "pro.go",
    "chars": 257,
    "preview": "//go:build pro\n\npackage goreplay\n\n// PRO this value indicates if goreplay is running in PRO mode..\n// it must not be mod"
  },
  {
    "path": "proto/fuzz.go",
    "chars": 97,
    "preview": "//go:build gofuzz\n\npackage proto\n\nfunc Fuzz(data []byte) int {\n\n\tParseHeaders(data)\n\n\treturn 1\n}\n"
  },
  {
    "path": "proto/proto.go",
    "chars": 15377,
    "preview": "/*\nPackage proto provides byte-level interaction with HTTP request payload.\n\nExample of HTTP payload for future referenc"
  },
  {
    "path": "proto/proto_test.go",
    "chars": 18208,
    "preview": "package proto\n\nimport (\n\t\"bytes\"\n\t\"net/textproto\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestHeader(t *testing.T) {\n\tvar payload,"
  },
  {
    "path": "protocol.go",
    "chars": 2063,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"encoding/hex\"\n\t\"fmt\"\n)\n\n// These constants help to indicate the typ"
  },
  {
    "path": "s3/index.html",
    "chars": 9873,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Gor PRO</title>\n\n    <style type=\"text/css\">\n/* file size: 10.6ko | optimized f"
  },
  {
    "path": "s3_reader.go",
    "chars": 2334,
    "preview": "package goreplay\n\nimport (\n\t\"bytes\"\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/aws/aws-sdk-go/aws\"\n\t\"github.com/aw"
  },
  {
    "path": "s3_test.go",
    "chars": 3504,
    "preview": "//go:build pro\n\npackage goreplay\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/a"
  },
  {
    "path": "settings.go",
    "chars": 24598,
    "preview": "package goreplay\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/buger/goreplay/internal/size\"\n)"
  },
  {
    "path": "settings_test.go",
    "chars": 180,
    "preview": "package goreplay\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc TestAppSettings(t *testing.T) {\n\ta := AppSettings{}\n\t_, e"
  },
  {
    "path": "sidenav.css",
    "chars": 8630,
    "preview": ".wy-affix {\n  position: fixed;\n  top: 1.618em;\n}\n\n.wy-menu a:hover {\n  text-decoration: none;\n}\n\n.wy-menu-vertical heade"
  },
  {
    "path": "site/.gitignore",
    "chars": 35,
    "preview": "_site\n.sass-cache\n.jekyll-metadata\n"
  },
  {
    "path": "site/Gemfile",
    "chars": 811,
    "preview": "source \"https://rubygems.org\"\nruby RUBY_VERSION\n\n# Hello! This is where you manage which Jekyll version is used to run.\n"
  },
  {
    "path": "site/_config.yml",
    "chars": 1402,
    "preview": "# Welcome to Jekyll!\n#\n# This config file is meant for settings that affect your whole blog, values\n# which you are expe"
  },
  {
    "path": "site/_posts/2017-01-06-welcome-to-jekyll.markdown",
    "chars": 1202,
    "preview": "---\nlayout: post\ntitle:  \"Welcome to Jekyll!\"\ndate:   2017-01-06 11:19:34 +0300\ncategories: jekyll update\n---\nYou’ll fin"
  },
  {
    "path": "site/about.md",
    "chars": 524,
    "preview": "---\nlayout: page\ntitle: About\npermalink: /about/\n---\n\nThis is the base Jekyll theme. You can find out more info about cu"
  },
  {
    "path": "site/index.md",
    "chars": 213,
    "preview": "---\n# You don't need to edit this file, it's empty on purpose.\n# Edit theme's home layout instead if you wanna make some"
  },
  {
    "path": "snapcraft.yaml",
    "chars": 1019,
    "preview": "name: goreplay\nversion: '1.0'\nsummary: GoReplay is an open-source tool for capturing and replaying live HTTP traffic \nde"
  },
  {
    "path": "tcp_client.go",
    "chars": 4044,
    "preview": "package goreplay\n\nimport (\n\t\"crypto/tls\"\n\t\"io\"\n\t\"net\"\n\t\"runtime/debug\"\n\t\"syscall\"\n\t\"time\"\n)\n\n// TCPClientConfig client c"
  },
  {
    "path": "test_input.go",
    "chars": 2659,
    "preview": "package goreplay\n\nimport (\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"math/rand\"\n\t\"time\"\n)\n\n// ErrorStopped is the error returned wh"
  },
  {
    "path": "test_output.go",
    "chars": 595,
    "preview": "package goreplay\n\ntype writeCallback func(*Message)\n\n// TestOutput used in testing to intercept any output into callback"
  },
  {
    "path": "version.go",
    "chars": 83,
    "preview": "package goreplay\n\n// VERSION the current version of goreplay\nvar VERSION = \"2.0.0\"\n"
  }
]

About this extraction

This page contains the full source code of the probelabs/goreplay GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 162 files (655.8 KB), approximately 203.4k tokens, and a symbol index with 748 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!