Full Code of tidwall/tile38 for AI

master 5b8ce586ab16 cached
152 files
1.0 MB
352.9k tokens
1191 symbols
1 requests
Download .txt
Showing preview only (1,075K chars total). Download the full file or copy to clipboard to get everything.
Repository: tidwall/tile38
Branch: master
Commit: 5b8ce586ab16
Files: 152
Total size: 1.0 MB

Directory structure:
gitextract_ljil7_jn/

├── .github/
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd/
│   ├── tile38-benchmark/
│   │   ├── az/
│   │   │   └── az.go
│   │   └── main.go
│   ├── tile38-cli/
│   │   └── main.go
│   ├── tile38-luamemtest/
│   │   └── main.go
│   └── tile38-server/
│       └── main.go
├── core/
│   ├── commands.go
│   ├── commands.json
│   ├── commands_gen.go
│   ├── commands_test.go
│   ├── gen.sh
│   └── version.go
├── go.mod
├── go.sum
├── internal/
│   ├── bing/
│   │   ├── bing.go
│   │   ├── bing_test.go
│   │   ├── ext.go
│   │   └── ext_test.go
│   ├── buffer/
│   │   ├── buffer.go
│   │   └── buffer_test.go
│   ├── clip/
│   │   ├── clip.go
│   │   ├── clip_test.go
│   │   ├── collection.go
│   │   ├── feature.go
│   │   ├── linestring.go
│   │   ├── point.go
│   │   ├── polygon.go
│   │   └── rect.go
│   ├── collection/
│   │   ├── collection.go
│   │   ├── collection_test.go
│   │   ├── geodesic.go
│   │   └── string.go
│   ├── deadline/
│   │   └── deadline.go
│   ├── endpoint/
│   │   ├── amqp.go
│   │   ├── cfqueue.go
│   │   ├── disque.go
│   │   ├── endpoint.go
│   │   ├── eventHub.go
│   │   ├── grpc.go
│   │   ├── http.go
│   │   ├── kafka.go
│   │   ├── local.go
│   │   ├── mqtt.go
│   │   ├── nats.go
│   │   ├── pubsub.go
│   │   ├── redis.go
│   │   ├── scram_client.go
│   │   └── sqs.go
│   ├── field/
│   │   ├── field.go
│   │   ├── field_test.go
│   │   ├── list_binary.go
│   │   ├── list_struct.go
│   │   └── list_test.go
│   ├── glob/
│   │   ├── glob.go
│   │   ├── glob_test.go
│   │   └── match.go
│   ├── hservice/
│   │   ├── gen.sh
│   │   ├── hservice.pb.go
│   │   └── hservice.proto
│   ├── log/
│   │   ├── log.go
│   │   └── log_test.go
│   ├── object/
│   │   ├── object_binary.go
│   │   ├── object_struct.go
│   │   └── object_test.go
│   ├── server/
│   │   ├── aof.go
│   │   ├── aofmigrate.go
│   │   ├── aofshrink.go
│   │   ├── bson.go
│   │   ├── bson_test.go
│   │   ├── checksum.go
│   │   ├── client.go
│   │   ├── config.go
│   │   ├── crud.go
│   │   ├── dev.go
│   │   ├── expire.go
│   │   ├── expr.go
│   │   ├── expression.go
│   │   ├── fence.go
│   │   ├── follow.go
│   │   ├── group.go
│   │   ├── hooks.go
│   │   ├── json.go
│   │   ├── json_test.go
│   │   ├── keys.go
│   │   ├── live.go
│   │   ├── metrics.go
│   │   ├── monitor.go
│   │   ├── must.go
│   │   ├── must_test.go
│   │   ├── mvt.go
│   │   ├── mvt_test.go
│   │   ├── output.go
│   │   ├── pubqueue.go
│   │   ├── pubsub.go
│   │   ├── readonly.go
│   │   ├── respconn.go
│   │   ├── scan.go
│   │   ├── scanner.go
│   │   ├── scanner_test.go
│   │   ├── scripts.go
│   │   ├── search.go
│   │   ├── server.go
│   │   ├── stats.go
│   │   ├── stats_cpu.go
│   │   ├── stats_cpu_darlin.go
│   │   ├── test.go
│   │   ├── token.go
│   │   └── token_test.go
│   ├── sstring/
│   │   ├── sstring.go
│   │   └── sstring_test.go
│   └── viewer/
│       ├── index.html
│       └── viewer.go
├── scripts/
│   ├── RELEASE.md
│   ├── build.sh
│   ├── docker-push.sh
│   ├── package.sh
│   └── test.sh
└── tests/
    ├── 107/
    │   ├── .gitignore
    │   ├── LINK
    │   └── main.go
    ├── 616/
    │   └── main.go
    ├── README.md
    ├── aof_legacy
    ├── aof_test.go
    ├── client_test.go
    ├── fence_roaming_test.go
    ├── fence_test.go
    ├── follower_test.go
    ├── json_test.go
    ├── keys_search_test.go
    ├── keys_test.go
    ├── metrics_test.go
    ├── mock_io_test.go
    ├── mock_test.go
    ├── monitor_test.go
    ├── proto_test.go
    ├── scripts_test.go
    ├── stats_test.go
    ├── testcmd_test.go
    ├── tests_test.go
    └── timeout_test.go

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

================================================
FILE: .github/CONTRIBUTING.md
================================================
## How to contribute to Tile38

Before getting starting with contributing, please know that we currently use [Tile38 Slack](https://tile38.com/slack) channel for casual questions and user chat.

### Did you find a bug?

- **Do not open up a GitHub issue if the bug is a security vulnerability in Tile38**. Sensitive security-related issues should be reported to [security@tile38.com](mailto:security@tile38.com).

- **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/tidwall/tile38/issues).
- If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/tidwall/tile38/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring.

### Did you fix whitespace, format code, or make a purely cosmetic patch?

Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Tile38 will generally not be accepted.

### Do you intend to add a new feature or change an existing one?

- New features will probably not be approved without prior discussion. If you need a specialized feature, make sure to express your willingness to fund the work and maintenance.
- Please do not open a pull request without filing an issue and/or discussing it with a maintainer beforehand.

Thanks!


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

**Expected behavior**
A clear and concise description of what you expected to happen.

**Logs**
If applicable, provide logs, panics, system messages to help explain your problem.

**Operating System (please complete the following information):**
 - OS: [e.g. Linux / Windows / Mac OS]
 - CPU: [e.g. amd64 / arm64 / Apple Silicon / Intel]
 - Version: [e.g. 1.19.0]
 - Container: [e.g. Docker / None]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
  - name: Community Support
    url: https://tile38.com/slack/
    about: Please ask and answer questions here.
  - name: Documenation Issues
    url: https://github.com/tile38/tile38.github.io/issues
    about: Please documenation related issues here.
 


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
Please do not open a pull request without first filing an issue and/or discussing the feature directly with the project maintainer.

### Please ensure you adhere to every item in this list

- [ ] This PR was pre-approved by the project maintainer
- [ ] I have self-reviewed the code
- [ ] I have added all necessary tests

### Describe your changes

Please provide detailed description of the changes.

### Issue number and link

Pull request require a prior issue with discussion. 
Include the issue number of link here.


================================================
FILE: .github/workflows/main.yml
================================================
name: Go

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Set up Go 1.x
        uses: actions/setup-go@v2
        with:
          go-version: ^1.25

      - name: Check out code
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Test
        run: make test

      - name: Package
        run: make package

      - name: Docker push
        env:
          DOCKER_LOGIN: tidwall
          DOCKER_USER: tile38
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
        run: ./scripts/docker-push.sh


================================================
FILE: .gitignore
================================================
.DS_Store
tile38-*
!cmd/tile38-*
*.test
data*/
coverage.out
packages/

# Ignore IDE folders
.idea/
.vscode/


================================================
FILE: CHANGELOG.md
================================================
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [1.37.0] = 2026-01-06
### Added
- #791: Add regexp to where expressions using '=~' (@TomDeVito)

### Fixed
- #793: Avoid NaN points and rects for insertions and searches (@krkeshav)
- #789: Fix LineString feature encoding to use all points (@metaxasa)
- 45496a0: Ensure strict resp clients for pubsub
- f6e6fae: Ignore -o json flag for HELLO command

### Updated
- 653e7a0: Bumped github.com/eclipse/paho.mqtt.golang
- 2a86b4b: Bumped golang.org/x/crypto

## [1.36.5] = 2025-10-05
### Added
- 5462de9: Add -o flag to auto set client output to json or resp #779 (@huangpeizhi2018)

### Fixed
- 8c27bd7: Fix 'outside' detect not firing when 'cross' is present

## [1.36.4] = 2025-10-03
### Fixed
- 8c9f56c: Fix leader hanging on sigterm #783 (@dobiadi)

## [1.36.3] = 2025-09-26
### Fixed
- 684ad73: Fix panic, move pubq init cond #782 (@ayaIbrahimm)
- cde0ef7: Do not throw Lua nil access error during scans

## [1.36.2] = 2025-09-04
### Fixed
- 653aea6: Add GeoJSON "properties" member for Lua filtering
- 70c244f: Make the String.match() function case insensitive

## [1.36.1] = 2025-08-28
### Updated
- 53bed30: Update lock strategy for faster writes 
- 40f58b0: Kafka Endpoint Improvement #778 (@ifiok)
- 82f4d24: Smaller vector tile sizes for polygons
- 5b21c24: Auto clip geometries at low zoom levels

## [1.36.0] = 2025-07-14
### Added
- 35bde95: Support for Cloudflare Queues endpoint #773 (@tobilg)
- a2afb21: Vector tile support (Mapbox vector tiles) #775

### Updated
- 56c70a1: Bumped github.com/golang-jwt/jwt/v4
- 86b698d: Updated Go dependencies
- f95fcab: Go 1.25

## [1.35.0] = 2025-06-16
### Added
- 4638279: Added NATS Jetstream acks, user credentials, and tls #770 (@VeryStrongFingers)

### Updated
- 3fe57a7; Use atomics for HEALTHZ command to remove contention.
- 3085316: Expose the 'this' property to WHERE clauses.

## [1.34.4] = 2025-05-08
### Fixed
- 977bf25: Fix issue with some startup flags not being read (@salilgupta1)

### Updated
- 86333cd: Bump golang.org/x/net #767

## [1.34.3] = 2025-04-16
### Fixed
- dd98481: Fix channel message delay #763 (@txtsd)

## [1.34.2] = 2025-04-01
### Updated
- a80eaf2: Upgrade to Go 1.24

### Fixed
- 556390e: Fix equality tests with WHERE clause for nested values
- 42e17a1: Fix channel test that sometimes stalls

### Security
- 0ecf097: Bump golang.org/x/net #765

## [1.34.1] = 2025-01-13
### Security
- 927f382: CVE-2024-45338 golang.org/x/net #762 (@tduong2049)
- 07389d8: CVE-2024-45337 golang.org/x/crypto #760

## [1.34.0] = 2024-12-09
### Added 
- 459b3e6: Added fifo support for SQS webhooks #759 (@crankycookie)

### Updated
- bed590b: Upgrade to Alpine 3.20 #757 (@tduong2049)
- 2b09508: Upgrade to Go 1.23

## [1.33.4] = 2024-11-05
### Fixed
- aa1caa6: Use zero for undefined fields in where expressions #754 (@unendingblue)

## [1.33.3] = 2024-09-29
### Fixed
- 2b080f4: Include field to INFO replication command output #752 (@Kilowhisky)

## [1.33.2] = 2024-08-02
### Fixed
- 2e3eaa7: Remove extra quote in ROLE command with JSON output #749 (@Kilowhisky)

## [1.33.1] = 2024-07-02
### Fixed
- 193bce1: Fix followers not receiving channel messages #468 (@hibooboo2, @trendstate, @DoisKoh)

## [1.33.0] = 2024-05-03
## Added
- #726: Add EXIST and FEXIST command (@Kilowhisky)

## Fixed
- #738: Add support for CORS in http requests (@Kilowhisky)
- #741: FSET transforms field names to lowercase (@unendingblue, @iwpnd)
- #736: Fix field floating point parsing misrepresentation (@Kilowhisky)

## Updated
- #733: golang.org/x/net
- #724: google.golang.org/protobuf

## [1.32.2] = 2024-02-14
### Fixed
- #714: Fix crash when mixing z-coord dimensionality in a geometry (@prathik)
- #717: Metric expired_keys never incremented (@undeadcat)
- Updated Go runtime to 1.22

## [1.32.1] = 2023-11-20
### Fixed
- #711: Updated dependencies to address security vulnerabilities (@hcmf-wice)
- #706: Add support for 'none' authentication for kafka while still allowing SSL (@Kilowhisky)
- #702: Fix AWS SQS base domain parsing for China region (@LLluma)

## [1.32.0] = 2023-07-31
### Added
- #686: Support the ROLE command (@Kilowhisky)

### Fixed
- #698: Allow AUTH while loading data (@Kilowhisky)
- #694: Allow PING in pubsub (@Kilowhisky)
- #692: Properly support replica_announce properties (@Kilowhisky)
- #691: HEALTHZ should not be AUTH protected (@Kilowhisky)
- #685: Heap size not coming down after objects are removed (@Mukund2900, @iwpnd)
- 0144ca6: Fix missing lock

## [1.31.0] = 2023-05-09
### Added
- #682: Enables cross platform building and pushing of docker images (arm64/amd64) (@eelcocramer)
- #680: Add hostname, port, output, and password env variables to tile38-cli (@ptsilva)

### Fixed
- #606: Only create AMQP queue and bindings for non-topic exchanges (@pacaj2am, @uwer)
- #672: Add graceful shutdown on SIGTERM (@dmitri-zganiaiko)

### Updated
- e9a0500: Upgrade to Go 1.20
- 05b2fb9: Security updates

## [1.30.2] = 2022-12-29
### Fixed
- #668: Fixed fields not persisting (@DucPhan2997)

## [1.30.1] = 2022-12-14
### Fixed
- a8c92a0: Speed up leader/follower replication
- e60ea70: Fix field names converting to lowercase

## [1.30.0] = 2022-11-22
### Added
- bdc80a7: Add WHERE expressions ([more info](https://tile38.com/topics/filter-expressions))
- f24c251: Allow for multiple MATCH patterns
- #652: Allow WHERE for geofence detection
- #657: Add distance to NEARBY IDS response (@iwpnd)
- #663: Lua Sanitization (@program--)

### Fixed
- 023433a: Fix server hang on shared address
- #655: fix: allow host ca sets for SASL and TLS connections (@iwpnd)

### Updated
- 7f2ce23: Upgrade to Go 1.19
- cbfb271: Updated data structures to use Go generics

## [1.29.2] = 2022-11-11
### Fixed
- #664: Fix bad line in inner ring response

## [1.29.1] = 2022-09-21
### Fixed
- fe180dc: Fix follower not authenticating after aofshink

## [1.29.0] = 2022-07-14
### Added
- b883f35: Add pending_events stat
- #643: Expose config and INFO response for replia-priorty (@rave-eserating)

### Fixed
- 8e61f81: Fixed test on Apple silicon

## [1.28.0] = 2022-04-12
### Added
- 10f8564: Added option to "not found" for DEL
- #633: Added "clear" command in the tile38-cli (@CaioDallaqua)
- #634: Added -x flag to tile38-cli (@sign0)

### Fixed
- #636: Workaround for the RESP3 Java lettuce client (@rave-eserating)
- a1cc8e6: Fix eof error for incomplete commands (Theresa D)

### Updated
- fcdb469: Security updates
- #638: Upgrade alpine in Dockerfile (@bb)
- a124738: Upgrade to Go 1.18
- 38ea913: Upgrade prometheous client
- 45fde6a: Upgraded nats dependencies

## [1.27.1] = 2021-01-04
### Fix
- b6833a2: Auto assign server_id for bootstrapped config files

## [1.27.0] = 2021-12-28
### Added
- #629: JSON logging (@iwpnd)
- 241117c: BUFFER option for WITHIN and INTERSECTS, see #79

## [1.26.4] = 2021-10-25
### Hotfix
- a7592f7: Bump version to match changelog

## [1.26.3] = 2021-10-25
### Updated
- a47443a: Upgrade tidwall modules

## [1.26.2] = 2021-10-22
### Added
- #625: Azure EventHub hook support

### Changed
- 11cea4d: Removed vendor directory

## [1.26.1] = 2021-10-01
### Updated
- 9e552c3: Allow some basic client commands before AOF data loads

## [1.26.0] = 2021-09-29
### Added
- #623: Added SECTOR type to spatial searches (@iwpnd, @gmonk)

### Fixed
- #624: AOFSHRINK causes panic on server (@saques)

## [1.25.5] = 2021-09-26
### Fixed
- 8ebcbeb: Fixed Z not matching on where clause for Feature/Point. (@tomquas)

## [1.25.4] = 2021-09-14
### Added
- a737a78: Add unix socket support

### Updated
- 8829b8f: Change hooks collection type from hashmap to btree
- 83094b2: Update hook expiration logic
- c686b87: Return hook ttl with HOOKS request
- 06a92d8: Increase the precision of TIMEOUT
- Upgrade to Go 1.17.1

## [1.25.3] = 2021-08-23
### Fixed
- #621: Fixed a memory leak (@Morgiflute)

### Updated
- Update B-tree library
- Upgrade to Go 1.17

## [1.25.2] = 2021-08-10
### Fixed
- #620: Fixed kafka authentication methods

### Updated
- Upgraded various dependencies

## [1.25.1] = 2021-07-22
### Fixed
- #618: Fixed NEARBY with SPARSE returning too many results. (@nesjett)

## [1.25.0] = 2021-07-12
### Added
- #504: Added TLS support for Nats webhook provider.
- #552: Add CLIPBY subcommand to INTERSECTS/WITHIN. (@rshura)
- #561: Added geofence webhook for GCP Pubsub. (@mscno)
- #615: Add SASL to Kafka provider. (@mathieux51, @iwpnd)

### Updated
- #551: Optimize field value access. (@mpoindexter)
- #554: Improved kNN using geodesic algorithm for NEARBY command. (@mpoindexter)

### Fixed
- #611: Close follower files before finishing aofshrink. (@mzbrau)
- #613: Fix Memory Leak in Kafka Producer. (@iwpnd)
- #616: Fixed expiration logic issue. (@Neuintown)

## [1.24.3] = 2021-06-09
### Fixed
- af43d5a: Hotfix. Fixed invalid healthz output.

## [1.24.2] = 2021-06-07
### Updated
- b610633: Update Go to 1.16

## [1.24.1] = 2021-06-07
### Added
- #609: Added HEALTHZ command (@iwpnd, @stevelacy)

## [1.24.0] = 2021-05-19
### Added
- #604: Added Prometheus metrics (@oliver006)

### Fixed
- #605: Remove deprecated threads flag (@cep-ter) 

## [1.23.0] = 2021-04-01
### Updated
- #598: Added TLS Config to Kafka (@iwpnd)
- #599: Include "distance" to output when user specifically requests (@iwpnd)
- #597: Allow for all command types for roaming event (@johnpmayer)
- 31a0fbd: Upgraded dependencies and moved to Go 1.16

### Fixed
- #600: Fix invalid queue.db error (@lokisisland)
- #603: Fix tile38-cli output showing protocol size when piping (@bb)

## [1.22.6] = 2021-02-07
### Updated
- 72dfaae: Updated various dependencies
- 016f397: Updated btree library, optimization 
- 4f8bc05: Updated rtree library, optimization

### Fixed
- 6092f73: Better handle connection errors in tile38-cli

## [1.22.5] = 2020-11-09
### Fixed
- 9ce2033: Fixed fields being shuffled after AOFSHRINK

## [1.22.4] = 2020-11-07
### Updated
- 1a7d8d6: Added ENV var for 500 http errors

## [1.22.3] = 2020-10-28
### Updated
- #583: Optimization for non-"cross" based geofence detection (@cliedeman)
- 79bee85: Replaced the underlying B-tree structure.

## [1.22.2] = 2020-10-07
### Fixed
- #230: Fix trailing zeros in AOF at startup

## [1.22.1] = 2020-09-22
### Updated
- 9a34a37: Updated Go version to 1.15
- b1dc463: Updated outdated dependencies (40 in total)

### Added
- #578 Fix "cross" detection not firing in some cases (@feichler-or)

## [1.22.0] = 2020-08-12
### Added
- #571 Added MONITOR command (@tomquas)

### Fixed
- #566: Fixed crash in fenceMatchRoam causing an index out of range panic (@larsw)
- #569: Fixed wrong order for fields with SCAN (@ipsusila)
- #573: Fixed crash with geohash precision above 12 (@superloach)
- 68e2b6d: Updated Kafka client to support (@LeonardoBonacci)

## [1.21.1] = 2020-06-04
### Fixed
- #564: Fix OUTPUT client command requiring authentication. (@LeonardoBonacci)

## [1.20.0] = 2020-05-20
### Updated
- #534: Avoid sorting fields for each written object. (@rshura)
- #544: Match geometry indexing to server config
- b3dc025: Optimize point in ring
- 3718cd7: Added priority option for AMQP endpoints

### Fixed
- #538: DEL geofence notifications are missing the "key" field
- #539: Fixed issue with some features not working with WITHIN (@rshura)
- #540: Fix a concurrent write/read on the server conn map (@mpoindexter)
- #543: Fix clipping empty rings (@rshura)
- #558: Fixed clip test (@mmcloughlin)
- #562: Crashes under go1.14 runtime
- ff48054: Fixed a missing faraway event for roaming geofences
- 5162ac5: Stable sort roam notifications

## [1.19.5] = 2020-02-11
### Fixed
- c567512: Fix packages not vendoring on build

## [1.19.4] = 2020-02-10
### Fixed
- #529: Fix linestring features behave diffrent with CIRCLE (@spierepf)

## [1.19.3] = 2019-12-11
### Fixed
- #513: Fix tile38-cli from freezing with non-quoted geojson (@duartejc)

## [1.19.2] = 2019-11-28
### Fixed
- 6f3716a: Fix false negative for intersecting rings (@thomascoquet)

## [1.19.1] = 2019-11-18
### Updated
- cfc65a1: Refactored repo, moved to Go modules, updated vendor dependencies.

### Fixed
- 9d27533: Fix infinite loop on tile38-cli connection failure.
- #509: Fixed panic on AOFSHRINK. (@jordanferenz)

## [1.19.0] = 2019-11-02
### Added
- #464: Add area expressions TEST command. (@rshura)

### Fixed
- #493: Fix invalid JSON when JSET strings that look like numbers. (@spierepf, @JordanArmstrong)
- #499: Fix invalid PubSub format when output is set to JSON. (@dmvass)
- #500: Fix Tile38-cli not propertly handling quotes. (@vthorsell)
- #502: Fix excessive memory usage for objects with TTLs. commit 23b016d. (@FreakyBytes)
- #503: Fix fprintf type error in stats_cpu.go for non-linux/darwin builds. (@JordanArmstrong)

### Changed
- #505: Update Travi-ci to use Go 1.13.x

## [1.18.0] = 2019-10-09
### Updated
- 639f6e2: Updated the spatial index (R-tree) implementation.

### Fixed
- b092cea: Fixed MQTT blocking on publish/wait.
- #496: Fixed MQTT client ID uniqueness. (@neterror)
- #497: Fixed data race on webhook map with TTLs. (@belek)
- #498: Fixed JSET cancels objects TTL expiry value. (@belek)

## [1.17.6] - 2019-08-22
### Fixed
- 3d96b17: Fixed periodic stop-the-world pauses for systems with large heaps.

## [1.17.5] - 2019-08-22
### Fixed
- #489: Fixed nearby count always one (@jkarjala)

## [1.17.4] - 2019-08-09
### Fixed
- #486: Fixed data condition on connections map (@saltatory)

## [1.17.3] - 2019-08-03
### Fixed
- #483: Fixed lua pool pruning (@rshura)
- f7888c1: Fixed malformed json for chans command

## [1.17.2] - 2019-06-28
### Fixed
- #422: Fixes NEARBY command distance normalization issue (@TrivikrAm-Pamarthi, @melbania)

## [1.17.1] - 2019-05-04
### Fixed
- #448: Fixed missing commands for unsubscribing from active channel (@githubfr)
- #454: Fixed colored output for fatalf (@olevole)
- #453: Fixed nearby json field results showing wrong data (@melbania)

## [1.17.0] - 2019-04-26
### Added
- #446: Added timeouts to allow prepending commands with a TIMEOUT option. (@rshura)

### Fixed
- #440: Fixed crash with fence ROAM (@githubfr)

### Changed
- 3ae5927: Removed experimental evio option

## [1.16.4] - 2019-03-19
### Fixed
- e1a7145: Hotfix. Do not ignore SIGHUP. Use the `--nohup` flag or `nohup` command.

## [1.16.3] - 2019-03-19
### Fixed
- #437: Fixed clients blocking while webook sending. (@tesujiro)

### Added
- #430: Support more SQS credential providers. (@tobilg)
- #435: Added pprof flags for optional memory and cpu diagnostics.
- e47540b: Added auth flag to tile38-benchmark.
- 5335aec: Allow for standard SQS URLs. (@tobilg)

## [1.16.2] - 2019-03-12
### Fixed
- #432: Ignore SIGHUP signals. (@abhit011)
- #433: Fixed nearby inaccuracy with geofence. (@stcktrce)
- #429: Memory optimization, recycle AOF buffer.
- 95a5556: Added periodic yielding to iterators. (@rshura)

## [1.16.1] - 2019-03-01
### Fixed
- #421: Nearby with MATCH is returning invalid results (@nithinkota)

## [1.16.0] - 2019-02-25
### Fixed
- #415: Fixed overlapping geofences sending notifcation to wrong endpoint. (@belek, @s32x)
- #412: Allow SERVER command for Lua scripts. (@1995parham)
- #410: Allow slashes in MQTT Topics (@pstuifzand)
- #409: Fixed bug in polygon clipping. (@rshura)
- 30f903b: Require properties member for geojson features. (@rshura)

### Added
- #409: Added TEST command for executing WITHIN and INTERSECTS on two objects. (@rshura)
- #407: Allow 201 & 202 status code on webhooks. (@s32x)
- #404: Adding more replication data to INFO response. (@s32x)

## [1.15.0] - 2019-01-16
### Fixed
- #403: JSON Output for INFO and CLIENT (@s32x)
- #401: Fixing KEYS command (@s32x)
- #398: Ensuring channel publish order (@s32x)
- d7d0baa: Fix roam fence missing

### Added
- #402: Adding ARM and ARM64 packages (@s32x)
- #399: Add RequireValid and update geojson dependency (@stevelacy)
- #396: Add distance_to function to the tile38 namespace in lua. (@rshura)
- #395: Add RENAME and RENAMENX commands. (@rshura)

## [1.14.4] - 2018-12-03
### Fixed
- #394: Hotfix MultiPolygon intersect failure. (@contra)
- #392: Fix TLS certs missing in Docker. (@vziukas, @s32x)

### Added
- Add extended server stats with SERVER EXT. (@s32x)
- Add Kafka key to match notication key. (@Joey92)
- Add optimized spatial index for fences

## [1.14.3] - 2018-11-20
### Fixed
- Hotfix SCRIPT LOAD not executing from cli. (@rshura)

## [1.14.2] - 2018-11-15
### Fixed
- #386: Fix version not being set at build. (@stevelacy)

## [1.14.1] - 2018-11-15
### Fixed
- #385: Add `version` to SERVER command response (@stevelacy)
- Hotfix replica sync needs flushing (@rshura)
- Fixed a bug where some AOF commands where corrupted during reload

## [1.14.0] - 2018-11-11
### Added
- INTERSECT/WITHIN optimization that may drastically improve searching polygons that have lots of points.
- Faster responses for write operations such as SET/DEL
- NEARBY now always returns objects from nearest to farthest (@rshura)
- kNN haversine distance optimization (@rshura)
- Evio networking beta using the "-evio yes" and "-threads num" flags

### Fixed
- #369: Fix poly in hole query

## [1.13.0] - 2018-08-29
### Added
- eef5f3c: Add geofence notifications over pub/sub channels
- 3a6f366: Add NODWELL keyword to roaming geofences
- #343: Add Nats endpoints (@lennycampino)
- #340: Add MQTT tls/cert options (@tobilg)
- #314: Add CLIP subcommand to INTERSECTS (@rshura)

### Changed
- 3ae26e3: Updated B-tree implementation
- 1d78a41: Updated R-tree implementation

## [1.12.3] - 2018-06-16
### Fixed
- #316: Fix AMQP and AMQPS webhook endpoints to support namespaces (@DeadWisdom)
- #318: Fix aofshrink crash on windows (@abhit011)
- #326: Fix sporadic kNN results when TTL is used (@pmaseberg)

## [1.12.2] - 2018-05-10
### Fixed
- #313: Hotfix intersect returning incorrect results (@stevelacy)

## [1.12.1] - 2018-04-30
### Fixed
- #300: Fix pdelhooks not persisting (@tobilg)
- #293: Fix kafka lockup issue (@Joey92)
- #301: Fix AMQP uri custom params not working (@tobilg)
- #302: Fix tile with zoom level over 63 panics (@rshura)
- b99cd39: Fix Sync hook msg ttl with server time

## [1.12.0] - 2018-04-12
### Added
- 11b42c0: Option to disable AOF or to use a custom path: #220 #223 #297 (@sign0, @umpc, @fmr683, @zhangfeng158)
- #296: Add Meta data to hooks command (@tobilg)

### Changed
- 11b42c0: Updated help menu and show more options

### Fixed
- #295: Intersects returning nothing in some cases (@fils)
- #294: HTTP requests stopped working (@zhangfeng158)
- 0aa04a1: Lotsa package not vendored

## [1.11.1] - 2018-03-16
### Added
- #272: Preserve Docker image tag history (@gechr)
- 9428b84: Added cpu and threads to SERVER stats

### Fixed
- #281: Linestring intersection failure (@contra)
- #280: Filter id match before kNN results (@sweco-semtne)
- #269: Safe atomic ints for arm32 (@gmonk63)
- #267: Optimization for multiploygons intersect queries (@contra)

## [1.11.0] - 2018-03-05
### Added
- #221: Add WHEREEVAL clause to scan/search commands (@rshura)

### Fixed
- #254: Add maxmemory protection to FSET (@rshura)
- #258: Clear expires on reset (@zycbobby)
- #268: Avoid bbox intersect for non-bbox objects (@contra)

## [1.10.1] - 2018-01-17
### Fixed
- #244: Fix issue with points not being detected inside MultiPolygons (@fazlul3003)
- #245: Precalculate and store bboxes for complex objects (@huangpeizhi)
- #246: Fix server crash when receiving zero arg commands (@behrad)

## [1.10.0] - 2017-12-18
### Added
- #221: Sqs endpoint (@lennycampino)
- #226: Lua scripting (@rshura) 
- #231: Allow setting multiple fields in a single fset command (@rshura)
- #235: Add json library (encode/decode methods) to lua. (@rshura)
- 26d0083: Update vendoring to use golang/dep 
- c8ed7ca: Add WHEREIN command (@rshura)
- d817814: Optimized network pipelining

### Fixed
- #237: Flush to file periodically (@rshura)
- #241: Point match on interior hole (@genesor)
- 920dc3a: Use atomic ints/bools
- 730502d: Set keepalive default to 300 seconds
- 1084c60: Apply limit on top of cursor (@rshura)

## [1.9.1] - 2017-08-16
### Added
- cd05708: Spatial index optimizations
- #208: Debug message for failed webhook notifications (@karnivas)
- #201: New ECHO command (@yorkxiao)
- #183: Include tile38-cli in Docker image (@jchamberlain)
- #121: Allow reads for disconnected followers (@octete)

### Fixed
- 3fae3f7: Allow cursors for kNN queries
- #211: Crash when shrinking AOF on Windows (@icewukong)
- #203: Lifted LIMIT restriction all queries and COUNT keyword (@yorkxiao, @FX-HAO)
- #207: Send empty results for queries on nonexistent keys (@FX-HAO)
- #195: Added kNN overscan ordering (@rshura)
- #199: Apply LIMIT after WHERE clause (@rshura)
- #199: Require Go 1.7 (@rshura)
- #198: Omit fields for Resp when NOFIELDS is used (@rshura)

## [1.9.0] - 2017-04-13
### Added
- #159: AMQP/RabbitMQ webhook support (@m1ome, @paavalan)
- #152: Kafka webhook support (@m1ome)
- #141: Add distances to Geofence notifications
- #54: New benchmark tool (@literadix, @Lars-Meijer, @m1ome)
- #20: Ability to specify pidfile via args (@olevole)

### Fixed
- b1c76d7: tile38-cli auto doesn't auto reconnect
- #156: Use redis-style TTL implementation (@Lars-Meijer, @m1ome)
- #150: Live "inside" fence event not triggering for new object (@phulst)

## [1.8.0] - 2017-02-21
### Added
- #145: TCP Keepalives option (@UriHendler)
- #136: K nearest neighbors for NEARBY command (@m1ome, @tomquas, @joernroeder)
- #139: Added CLIENT command (@UriHendler)
- #133: AutoGC config option (@m1ome, @amorskoy)

### Fixed
- #147: Leaking http hook connections (@mkabischev)
- #143: Duplicate data in hook data (@mkabischev)

## [1.7.5] - 2017-01-13
### Added
- Performance bump for all SET commands, ~10% faster
- Lower memory footprint for large datasets
- #112: Added distance to NEARBY command (@m1ome, @auselen)
- #123: Redis endpoint for webhooks (@m1ome)
- #128: Allow disabling HTTP & WebSocket transport (@m1ome)

### Fixed
- #116: Missing response in TTL json command (@phulst)
- #117: Error in command documentation (@juanpabloaj)
- #118: Unexpected EOF bug with websockets (@m1ome)
- #122: Disque typo timeout handling (@m1ome)
- #127: 3d object searches with 2d geojson area (@damariei)

## [1.7.0] - 2016-12-29
### Added
- #104: PDEL command - Selete objects that match a pattern (@GameFreedom)
- #99: COMMAND keyword for masking geofences by command type (@amorskoy)
- #96: SCAN keyword for roaming geofences
- fba34a9: JSET, JGET, JDEL commands

### Fixed
- #107: Memory leak (@amorskoy)
- #98: Output json fix

## [1.6.0] - 2016-12-11
### Added
- #87: Fencing event grouping (@huangpeizhi)

### Fixed
- #91: Wrong winding order for CirclePolygon function (@antonioromano)
- #73: Corruption for AOFSHRINK (@huangpeizhi)
- #71: Lower memory usage. About 25% savings (@thisisaaronland, @umpc)
- Polygon raycast bug. tidwall/poly#1 (@drewlesueur)
- Added black-box testing

## [1.5.4] - 2016-11-17
### Fixed
- #84: Hotfix - roaming fence deadlock (@tomquas)

## [1.5.3] - 2016-11-16
### Added
- #4: Official docker support (@gordysc)

### Fixed
- #77: NX/XX bug (@damariei)
- #76: Match on prefix star (@GameFreedom, @icewukong)
- #82: Allow for precise search for strings (@GameFreedom)
- #83: Faster congruent modulo for points (@icewukong, @umpc)

## [1.5.2] - 2016-10-20
### Fixed
- #70: Invalid results for INTERSECTS query (@thisisaaronland)

## [1.5.1] - 2016-10-19
### Fixed
- #67: Call the EXPIRE command hangs the server (@PapaStifflera)
- #64: Missing points in 'Nearby' queries (@umpc)

## [1.5.0] - 2016-10-03
### Added
- #61: Optimized queries on 3d objects (@damariei)
- #60: Added [NX|XX] keywords to SET command (@damariei)
- #29: Generalized hook interface (@jeremytregunna)
- GRPC geofence hook support 

### Fixed
- #62: Potential Replace Bug Corrupting the Index (@umpc)
- #57: CRLF codes in info after bump from 1.3.0 to 1.4.2 (@olevole)

## [1.4.2] - 2016-08-26
### Fixed
- #49. Allow fragmented pipeline requests (@owaaa)
- #51: Allow multispace delim in native proto (@huangpeizhi)
- #50: MATCH with slashes (@huangpeizhi)
- #43: Linestring nearby search correction (@owaaa)

## [1.4.1] - 2016-08-26
### Added
- #34: Added "BOUNDS key" command (@icewukong)

### Fixed
- #38: Allow for nginx support (@GameFreedom)
- #39: Reset requirepass (@GameFreedom)

## [1.3.0] - 2016-07-22
### Added
- New EXPIRE, PERSISTS, TTL commands. New EX keyword to SET command
- Support for plain strings using `SET ... STRING value.` syntax
- New SEARCH command for finding strings
- Scans can now order descending

### Fixed
- #28: fix windows cli issue (@zhangkaizhao)

## [1.2.0] - 2016-05-24
### Added
- #17: Roaming Geofences for NEARBY command (@ElectroCamel, @davidxv)
- #15: maxmemory config setting (@jrots)

## [1.1.4] - 2016-04-19
### Fixed
- #12: Issue where a newline was being added to HTTP POST requests (@davidxv)
- #13: OBJECT keyword not accepted for WITHIN command (@ray93)
- Panic on missing key for search requests

## [1.1.2] - 2016-04-12
### Fixed
- A glob suffix wildcard can result in extra hits
- The native live geofence sometimes fails connections

## [1.1.0] - 2016-04-02
### Added
- Resp client support. All major programming languages now supported
- Added WITHFIELDS option to GET
- Added OUTPUT command to allow for outputing JSON when using RESP
- Added DETECT option to geofences

### Changed
- New AOF file structure.
- Quicker and safer AOFSHRINK.

### Deprecation Warning
- Native protocol support is being deprecated in a future release in favor of RESP


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

Thanks for your interest in improving Tile38!

## Issues
- **Found a bug?** Please open an issue with a clear description and precise steps to reproduce.

## Pull Requests
- **Scope.** PRs are welcome for bug fixes and small, low-risk changes.
- **Please coordinate first.** For large changes, such as new features, please file an issue and/or discuss it with a maintainer beforehand.
- **Quality.** Keep PRs focused, include tests (where applicable), and update docs.

## When Not to use a Pull Request

Do NOT submit a Pull Request for:

- Security-related changes.
- Works in progress.
- Changes that require design discussion, or are likely to be controversial.
- Changes needing specialized or cross-subsystem review.
- Large refactors or mechanical tree-wide changes.
- Changes generated by AI tools.

## AI Assisted Contributions

We are not accepting AI assisted code into Tile38 at this time. 
This policy may change in the future. 
Please reach out if you have any questions or concerns regarding AI and Tile38.

### Contributor Responsibilities

- Monitor your Pull Request and respond to review feedback promptly.
- Pull Requests may be closed if there is no response for **one month**.

By submitting a contribution, you confirm you have the right to do so and grant Tile38 LLC the rights needed to use, modify, and redistribute your contribution as part of the project.

If you have any questions or concerns regarding licensing, please contact us at licensing@tile38.com.  
For all other questions, contributing@tile38.com.


================================================
FILE: Dockerfile
================================================
FROM alpine:3.20

ARG VERSION
ARG TARGETOS
ARG TARGETARCH

RUN apk add --no-cache ca-certificates

ADD packages/tile38-$VERSION-$TARGETOS-$TARGETARCH/tile38-server /usr/local/bin
ADD packages/tile38-$VERSION-$TARGETOS-$TARGETARCH/tile38-cli /usr/local/bin
ADD packages/tile38-$VERSION-$TARGETOS-$TARGETARCH/tile38-benchmark /usr/local/bin

RUN addgroup -S tile38 && \
    adduser -S -G tile38 tile38 && \
    mkdir /data && chown tile38:tile38 /data

VOLUME /data

EXPOSE 9851
CMD ["tile38-server", "-d", "/data"]


================================================
FILE: LICENSE
================================================
Copyright (c) 2016 Josh Baker

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: Makefile
================================================
all: tile38-server tile38-cli tile38-benchmark tile38-luamemtest

.PHONY: tile38-server
tile38-server:
	@./scripts/build.sh tile38-server

.PHONY: tile38-cli
tile38-cli:
	@./scripts/build.sh tile38-cli

.PHONY: tile38-benchmark
tile38-benchmark:
	@./scripts/build.sh tile38-benchmark

.PHONY: tile38-luamemtest
tile38-luamemtest:
	@./scripts/build.sh tile38-luamemtest

test: all
	@./scripts/test.sh

package:
	@rm -rf packages/
	@scripts/package.sh Windows windows amd64
	@scripts/package.sh Mac     darwin  amd64
	@scripts/package.sh Linux   linux   amd64
	@scripts/package.sh FreeBSD freebsd amd64
	@scripts/package.sh ARM     linux   arm
	@scripts/package.sh ARM64   linux   arm64

clean:
	rm -rf tile38-server tile38-cli tile38-benchmark tile38-luamemtest 

distclean: clean
	rm -rf packages/

install: all
	cp tile38-server /usr/local/bin
	cp tile38-cli /usr/local/bin
	cp tile38-benchmark /usr/local/bin

uninstall: 
	rm -f /usr/local/bin/tile38-server
	rm -f /usr/local/bin/tile38-cli
	rm -f /usr/local/bin/tile38-benchmark


================================================
FILE: README.md
================================================
<p align="center">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="/.github/images/logo-dark.svg">
  <source media="(prefers-color-scheme: light)" srcset="/.github/images/logo-light.svg">
  <img alt="Tile38" src="/.github/images/logo-light.svg" width="284">
</picture>
</p>
<p align="center">
<a href="https://tile38.com/slack/"><img src="https://img.shields.io/badge/Slack-4A154B?logo=slack&logoColor=fff" alt="Slack"></a>
<a href="https://discord.gg/esq8ESgzms"><img src="https://img.shields.io/badge/Discord-%235865F2.svg?&logo=discord&logoColor=white" alt="Discord"></a>
</p>




Tile38 is an open source (MIT licensed), in-memory geolocation data store, spatial index, and realtime geofencing server.
It supports a variety of object types including lat/lon points, bounding boxes, XYZ tiles, Geohashes, and GeoJSON. 

<p align="center">
<i>This README is quick start document. You can find detailed documentation at <a href="https://tile38.com">https://tile38.com</a>.</i><br><br>
<a href="#searching"><img src="/.github/images/search-nearby.png" alt="Nearby" border="0" width="120" height="120"></a>
<a href="#searching"><img src="/.github/images/search-within.png" alt="Within" border="0" width="120" height="120"></a>
<a href="#searching"><img src="/.github/images/search-intersects.png" alt="Intersects" border="0" width="120" height="120"></a>
<a href="https://tile38.com/topics/geofencing"><img src="/.github/images/geofence.gif" alt="Geofencing" border="0" width="120" height="120"></a>
<a href="https://tile38.com/topics/roaming-geofences"><img src="/.github/images/roaming.gif" alt="Roaming Geofences" border="0" width="120" height="120"></a>
</p>

## Features

- Spatial index with [search](#searching) methods such as Nearby, Within, and Intersects.
- Realtime [geofencing](#geofencing) through [webhooks](https://tile38.com/commands/sethook) or [pub/sub channels](#pubsub-channels).
- Object types of [lat/lon](#latlon-point), [bbox](#bounding-box), [Geohash](#geohash), [GeoJSON](#geojson), [QuadKey](#quadkey), and [XYZ tile](#xyz-tile).
- Support for lots of [Clients Libraries](#tile38-client-libraries) written in many different languages.
- Variety of protocols, including [http](#http) (curl), [websockets](#websockets), [telnet](#telnet), and the [Redis RESP](https://redis.io/topics/protocol).
- Server responses are [RESP](https://redis.io/topics/protocol) or [JSON](https://www.json.org).
- Full [command line interface](#cli).
- Leader / follower [replication](#replication).
- In-memory database that persists on disk.

## Components
- tile38-server: The server
- tile38-cli: Command line interface tool
- tile38-benchmark: Server benchmark tool

## Getting Started

### Getting Tile38

Perhaps the easiest way to get the latest Tile38 is to use one of the pre-built release binaries which are available for OSX, Linux, FreeBSD, and Windows. Instructions for using these binaries are on the GitHub [releases page](https://github.com/tidwall/tile38/releases).

### Docker 

To run the latest stable version of Tile38:

```
docker pull tile38/tile38
docker run -p 9851:9851 tile38/tile38
```

Visit the [Tile38 hub page](https://hub.docker.com/r/tile38/tile38/) for more information.

### Homebrew (macOS)

Install Tile38 using [Homebrew](https://brew.sh/)

```sh
brew install tile38
tile38-server
```

### Building Tile38 

Tile38 can be compiled and used on Linux, OSX, Windows, FreeBSD, and probably others since the codebase is 100% Go. We support both 32 bit and 64 bit systems. [Go](https://golang.org/dl/) must be installed on the build machine.

To build everything simply:
```
$ make
```

To test:
```
$ make test
```

### Running 
For command line options invoke:
```
$ ./tile38-server -h
```

To run a single server:

```
$ ./tile38-server

# The tile38 shell connects to localhost:9851
$ ./tile38-cli
> help
```

#### Prometheus Metrics
Tile38 can natively export Prometheus metrics by setting the `--metrics-addr` command line flag (disabled by default). This example exposes the HTTP metrics server on port 4321:
```
# start server and enable Prometheus metrics, listen on local interface only
./tile38-server --metrics-addr=127.0.0.1:4321

# access metrics
curl http://127.0.0.1:4321/metrics
```
If you need to access the `/metrics` endpoint from a different host you'll have to set the flag accordingly, e.g. set it to `0.0.0.0:<<port>>` to listen on all interfaces.

Use the [redis_exporter](https://github.com/oliver006/redis_exporter) for more advanced use cases like extracting key values or running a lua script.


## <a name="cli"></a>Playing with Tile38

Basic operations:
```
$ ./tile38-cli

# add a couple of points named 'truck1' and 'truck2' to a collection named 'fleet'.
> set fleet truck1 point 33.5123 -112.2693   # on the Loop 101 in Phoenix
> set fleet truck2 point 33.4626 -112.1695   # on the I-10 in Phoenix

# search the 'fleet' collection.
> scan fleet                                 # returns both trucks in 'fleet'
> nearby fleet point 33.462 -112.268 6000    # search 6 kilometers around a point. returns one truck.

# key value operations
> get fleet truck1                           # returns 'truck1'
> del fleet truck2                           # deletes 'truck2'
> drop fleet                                 # removes all 
```

Tile38 has a ton of [great commands](https://tile38.com/commands).

## Fields
Fields are extra data that belongs to an object. A field is always a double precision floating point. There is no limit to the number of fields that an object can have. 

To set a field when setting an object:
```
> set fleet truck1 field speed 90 point 33.5123 -112.2693             
> set fleet truck1 field speed 90 field age 21 point 33.5123 -112.2693
```

To set a field when an object already exists:
```
> fset fleet truck1 speed 90
```

To get a field when an object already exists:
```
> fget fleet truck1 speed
```

## Searching

Tile38 has support to search for objects and points that are within or intersects other objects. All object types can be searched including Polygons, MultiPolygons, GeometryCollections, etc.

<img src="/.github/images/search-within.png" width="200" height="200" border="0" alt="Search Within" align="left">

#### Within 
WITHIN searches a collection for objects that are fully contained inside a specified bounding area.
<BR CLEAR="ALL">

<img src="/.github/images/search-intersects.png" width="200" height="200" border="0" alt="Search Intersects" align="left">

#### Intersects
INTERSECTS searches a collection for objects that intersect a specified bounding area.
<BR CLEAR="ALL">

<img src="/.github/images/search-nearby.png" width="200" height="200" border="0" alt="Search Nearby" align="left">

#### Nearby
NEARBY searches a collection for objects that intersect a specified radius.
<BR CLEAR="ALL">

### Search options
**WHERE** - This option allows for filtering out results based on [field](#fields) values. For example<br>```nearby fleet where speed 70 +inf point 33.462 -112.268 6000``` will return only the objects in the 'fleet' collection that are within the 6 km radius **and** have a field named `speed` that is greater than `70`. <br><br>Multiple WHEREs are concatenated as **and** clauses. ```WHERE speed 70 +inf WHERE age -inf 24``` would be interpreted as *speed is over 70 <b>and</b> age is less than 24.*<br><br>The default value for a field is always `0`. Thus if you do a WHERE on the field `speed` and an object does not have that field set, the server will pretend that the object does and that the value is Zero.<br><br>WHERE expressions support the `=~` operator for regex matching. It uses Go's re2 regular expression engine to match string values in fields or GeoJSON properties within objects. For example, `WHERE properties.name =~ 'truck.*'` filters objects where the 'name' property matches the pattern, and `WHERE field_name =~ 'value.*'` works similarly for fields.

**MATCH** - MATCH is similar to WHERE except that it works on the object id instead of fields.<br>```nearby fleet match truck* point 33.462 -112.268 6000``` will return only the objects in the 'fleet' collection that are within the 6 km radius **and** have an object id that starts with `truck`. There can be multiple MATCH options in a single search. The MATCH value is a simple [glob pattern](https://en.wikipedia.org/wiki/Glob_(programming)).

**CURSOR** - CURSOR is used to iterate though many objects from the search results. An iteration begins when the CURSOR is set to Zero or not included with the request, and completes when the cursor returned by the server is Zero.

**NOFIELDS** - NOFIELDS tells the server that you do not want field values returned with the search results.

**LIMIT** - LIMIT can be used to limit the number of objects returned for a single search request.


## Geofencing

<img src="/.github/images/geofence.gif" width="200" height="200" border="0" alt="Geofence animation" align="left">
A <a href="https://en.wikipedia.org/wiki/Geo-fence">geofence</a> is a virtual boundary that can detect when an object enters or exits the area. This boundary can be a radius, bounding box, or a polygon. Tile38 can turn any standard search into a geofence monitor by adding the FENCE keyword to the search. 

*Tile38 also allows for [Webhooks](https://tile38.com/commands/sethook) to be assigned to Geofences.*

<br clear="all">

A simple example:
```
> nearby fleet fence point 33.462 -112.268 6000
```
This command opens a geofence that monitors the 'fleet' collection. The server will respond with:
```
{"ok":true,"live":true}
```
And the connection will be kept open. If any object enters or exits the 6 km radius around `33.462,-112.268` the server will respond in realtime with a message such as:

```
{"command":"set","detect":"enter","id":"truck02","object":{"type":"Point","coordinates":[-112.2695,33.4626]}}
```

The server will notify the client if the `command` is `del | set | drop`. 

- `del` notifies the client that an object has been deleted from the collection that is being fenced.
- `drop` notifies the client that the entire collection is dropped.
- `set` notifies the client that an object has been added or updated, and when it's position is detected by the fence.

The `detect` may be one of the following values.

- `inside` is when an object is inside the specified area.
- `outside` is when an object is outside the specified area.
- `enter` is when an object that **was not** previously in the fence has entered the area.
- `exit` is when an object that **was** previously in the fence has exited the area.
- `cross` is when an object that **was not** previously in the fence has entered **and** exited the area.

These can be used when establishing a geofence, to pre-filter responses. For instance, to limit responses to `enter` and `exit` detections:

```
> nearby fleet fence detect enter,exit point 33.462 -112.268 6000
```

### Pub/sub channels

Tile38 supports delivering geofence notifications over pub/sub channels. 

To create a static geofence that sends notifications when a bus is within 200 meters of a point and sends to the `busstop` channel:

```
> setchan busstop nearby buses fence point 33.5123 -112.2693 200
```

Subscribe on the `busstop` channel:

```
> subscribe busstop
```

## Object types

All object types except for XYZ Tiles and QuadKeys can be stored in a collection. XYZ Tiles and QuadKeys are reserved for the SEARCH keyword only.

#### Lat/lon point
The most basic object type is a point that is composed of a latitude and a longitude. There is an optional `z` member that may be used for auxiliary data such as elevation or a timestamp.
```
set fleet truck1 point 33.5123 -112.2693     # plain lat/lon
set fleet truck1 point 33.5123 -112.2693 225 # lat/lon with z member
```

#### Bounding box
A bounding box consists of two points. The first being the southwestern most point and the second is the northeastern most point.
```
set fleet truck1 bounds 30 -110 40 -100
```
#### Geohash
A [geohash](https://en.wikipedia.org/wiki/Geohash) is a string representation of a point. With the length of the string indicating the precision of the point. 
```
set fleet truck1 hash 9tbnthxzr # this would be equivalent to 'point 33.5123 -112.2693'
```

#### GeoJSON
[GeoJSON](https://tools.ietf.org/html/rfc7946) is an industry standard format for representing a variety of object types including a point, multipoint, linestring, multilinestring, polygon, multipolygon, geometrycollection, feature, and featurecollection.

<i>* All ignored members will not persist.</i>

**Important to note that all coordinates are in Longitude, Latitude order.**

```
set city tempe object {"type":"Polygon","coordinates":[[[0,0],[10,10],[10,0],[0,0]]]}
```

#### XYZ Tile
An XYZ tile is rectangle bounding area on earth that is represented by an X, Y coordinate and a Z (zoom) level.
Check out [maptiler.org](http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/) for an interactive example.

#### QuadKey
A QuadKey used the same coordinate system as an XYZ tile except that the string representation is a string characters composed of 0, 1, 2, or 3. For a detailed explanation checkout [The Bing Maps Tile System](https://msdn.microsoft.com/en-us/library/bb259689.aspx).

## Network protocols

It's recommended to use a [client library](#tile38-client-libraries) or the [Tile38 CLI](#running), but there are times when only HTTP is available or when you need to test from a remote terminal. In those cases we provide an HTTP and telnet options.

#### HTTP
One of the simplest ways to call a tile38 command is to use HTTP. From the command line you can use [curl](https://curl.haxx.se/). For example:

```
# call with request in the body
curl --data "set fleet truck3 point 33.4762 -112.10923" localhost:9851

# call with request in the url path
curl localhost:9851/set+fleet+truck3+point+33.4762+-112.10923
```

#### Websockets
Websockets can be used when you need to Geofence and keep the connection alive. It works just like the HTTP example above, with the exception that the connection stays alive and the data is sent from the server as text websocket messages.

#### Telnet
There is the option to use a plain telnet connection. The default output through telnet is [RESP](https://redis.io/topics/protocol).

```
telnet localhost 9851
set fleet truck3 point 33.4762 -112.10923
+OK

```

The server will respond in [JSON](https://json.org) or [RESP](https://redis.io/topics/protocol) depending on which protocol is used when initiating the first command.

- HTTP and Websockets use JSON. 
- Telnet and RESP clients use RESP.

## Tile38 Client Libraries

The following clients are built specifically for Tile38.  
Clients that support most Tile38 features are marked with a ⭐️.

- ⭐️ Go: [xjem/t38c](https://github.com/xjem/t38c)
- ⭐️ Node.js: [node-tile38](https://github.com/phulst/node-tile38) ([example code](https://github.com/tidwall/tile38/wiki/Node.js-example-(node-tile38)))
- ⭐️ Python: [pyle38](https://github.com/iwpnd/pyle38)
- ⭐️ TypeScript: [tile38-ts](https://github.com/iwpnd/tile38-ts)
- Go: [cjkreklow/t38c](https://github.com/cjkreklow/t38c)
- Python: [pytile38](https://github.com/mitghi/pytile38)
- Rust: [nazar](https://github.com/younisshah/nazar)
- Swift: [Talon](https://github.com/mikekinney/Talon)
- Java: [tile38-client-java](https://github.com/jamshidrostami/tile38-client-java)
- Java: [tile38-client](https://github.com/HkMoyun/tile38-client)

## Redis Client Libraries

Tile38 uses the [Redis RESP](https://redis.io/topics/protocol) protocol natively. 
Therefore most clients that support basic Redis commands will also support Tile38.

- C: [hiredis](https://github.com/redis/hiredis)
- C#: [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis)
- C++: [redox](https://github.com/hmartiro/redox)
- Clojure: [carmine](https://github.com/ptaoussanis/carmine)
- Common Lisp: [CL-Redis](https://github.com/vseloved/cl-redis)
- Erlang: [Eredis](https://github.com/wooga/eredis)
- Go: [go-redis](https://github.com/go-redis/redis) ([example code](https://github.com/tidwall/tile38/wiki/Go-example-(go-redis)))
- Go: [redigo](https://github.com/gomodule/redigo) ([example code](https://github.com/tidwall/tile38/wiki/Go-example-(redigo)))
- Haskell: [hedis](https://github.com/informatikr/hedis)
- Java: [lettuce](https://github.com/mp911de/lettuce) ([example code](https://github.com/tidwall/tile38/wiki/Java-example-(lettuce)))
- Node.js: [node_redis](https://github.com/NodeRedis/node_redis) ([example code](https://github.com/tidwall/tile38/wiki/Node.js-example-(node-redis)))
- Perl: [perl-redis](https://github.com/PerlRedis/perl-redis)
- PHP: [tinyredisclient](https://github.com/ptrofimov/tinyredisclient) ([example code](https://github.com/tidwall/tile38/wiki/PHP-example-(tinyredisclient)))
- PHP: [phpredis](https://github.com/phpredis/phpredis)
- Python: [redis-py](https://github.com/andymccurdy/redis-py) ([example code](https://github.com/tidwall/tile38/wiki/Python-example))
- Ruby: [redic](https://github.com/amakawa/redic) ([example code](https://github.com/tidwall/tile38/wiki/Ruby-example-(redic)))
- Ruby: [redis-rb](https://github.com/redis/redis-rb) ([example code](https://github.com/tidwall/tile38/wiki/Ruby-example-(redis-rb)))
- Rust: [redis-rs](https://github.com/mitsuhiko/redis-rs)
- Scala: [scala-redis](https://github.com/debasishg/scala-redis)
- Swift: [Redbird](https://github.com/czechboy0/Redbird)

## Contact

Josh Baker [@tidwall](https://twitter.com/tidwall)

## License

Tile38 source code is available under the MIT [License](/LICENSE).


================================================
FILE: cmd/tile38-benchmark/az/az.go
================================================
package az

// JSON is GeoJSON
var JSON = `
{ "type": "MultiPolygon", "coordinates": [ [ [ [ -114.635458, 34.876902 ], [ -114.636768000000103, 34.885705 ], [ -114.636725, 34.889107 ], [ -114.635425, 34.895192 ], [ -114.63185, 34.903942 ], [ -114.630877, 34.907263 ], [ -114.630552, 34.911852 ], [ -114.631537, 34.916153 ], [ -114.633237, 34.92123 ], [ -114.633253, 34.924608 ], [ -114.632196, 34.930628 ], [ -114.629753, 34.938684 ], [ -114.629811, 34.94481 ], [ -114.631681, 34.95131 ], [ -114.634274, 34.956662 ], [ -114.634953, 34.958918 ], [ -114.635237000000103, 34.965149 ], [ -114.634607, 34.96906 ], [ -114.629907, 34.980791 ], [ -114.629129, 34.986132 ], [ -114.629443, 34.991825 ], [ -114.630244000000104, 34.99464 ], [ -114.631807, 34.998632 ], [ -114.632665, 34.999806 ], [ -114.635570000000101, 35.005933 ], [ -114.637071, 35.010371 ], [ -114.637769, 35.014948 ], [ -114.63819, 35.022069 ], [ -114.637524, 35.027053 ], [ -114.633715, 35.035602 ], [ -114.629027, 35.042531 ], [ -114.625799, 35.045834 ], [ -114.615902, 35.05272 ], [ -114.610701000000105, 35.055458 ], [ -114.606694, 35.058941 ], [ -114.604715, 35.061744 ], [ -114.603619, 35.064226 ], [ -114.602908, 35.068588 ], [ -114.603175, 35.070445 ], [ -114.604736, 35.07483 ], [ -114.607701, 35.078533 ], [ -114.613132, 35.083097 ], [ -114.61842, 35.086539 ], [ -114.622517, 35.088703 ], [ -114.632053, 35.092559 ], [ -114.63937, 35.094733 ], [ -114.642831, 35.096503 ], [ -114.646579, 35.10082 ], [ -114.646764, 35.101868 ], [ -114.645152, 35.104995 ], [ -114.644354, 35.105903 ], [ -114.641116, 35.108401 ], [ -114.637432000000103, 35.112489 ], [ -114.632282, 35.117088 ], [ -114.628427, 35.118943 ], [ -114.623761, 35.120602 ], [ -114.628993, 35.119411 ], [ -114.624954000000102, 35.120742 ], [ -114.618697, 35.121749 ], [ -114.604007, 35.121252 ], [ -114.60274, 35.121666 ], [ -114.597794, 35.121735 ], [ -114.589787, 35.123522 ], [ -114.584877, 35.125194 ], [ -114.579882, 35.127506 ], [ -114.578263, 35.12881 ], [ -114.577146, 35.130982 ], [ -114.574411, 35.13495 ], [ -114.572597, 35.139557 ], [ -114.573706, 35.142698 ], [ -114.573879, 35.145351 ], [ -114.569529, 35.162317 ], [ -114.56876, 35.172195 ], [ -114.569214, 35.17289 ], [ -114.568989, 35.175085 ], [ -114.569258, 35.183424 ], [ -114.569653, 35.186267 ], [ -114.571404, 35.191026 ], [ -114.572084, 35.200794 ], [ -114.574037, 35.20379 ], [ -114.574233, 35.205481 ], [ -114.574958, 35.206714 ], [ -114.578581, 35.208113 ], [ -114.579535, 35.208911 ], [ -114.579897000000102, 35.21097 ], [ -114.580312, 35.220095 ], [ -114.583523, 35.230348 ], [ -114.58248, 35.233173 ], [ -114.582842, 35.238703 ], [ -114.584993, 35.242717 ], [ -114.586053, 35.248891 ], [ -114.585714, 35.253145 ], [ -114.585768, 35.257743 ], [ -114.586604, 35.262386 ], [ -114.587497, 35.265473 ], [ -114.590513, 35.272334 ], [ -114.593247, 35.284361 ], [ -114.595705, 35.289939 ], [ -114.596682, 35.294557 ], [ -114.597268, 35.299565 ], [ -114.59721, 35.303223 ], [ -114.595163, 35.321883 ], [ -114.595553, 35.326547 ], [ -114.599771, 35.34111 ], [ -114.604607, 35.355239 ], [ -114.606173, 35.359651 ], [ -114.611206, 35.370119 ], [ -114.617698, 35.380131 ], [ -114.618257, 35.382646 ], [ -114.618984, 35.389391 ], [ -114.620887, 35.396867 ], [ -114.621783, 35.39945 ], [ -114.625702, 35.407976 ], [ -114.626765, 35.409644 ], [ -114.629061000000107, 35.411175 ], [ -114.65208, 35.430134 ], [ -114.653817, 35.432853 ], [ -114.654295, 35.436854 ], [ -114.658105, 35.441835 ], [ -114.661747, 35.444735 ], [ -114.662896, 35.446449 ], [ -114.663934, 35.449466 ], [ -114.664215, 35.451707 ], [ -114.663880000000105, 35.454657 ], [ -114.664217, 35.455845 ], [ -114.665142, 35.457331 ], [ -114.666151, 35.458198 ], [ -114.667217, 35.46037 ], [ -114.666769000000102, 35.462085 ], [ -114.665790000000101, 35.463915 ], [ -114.665651, 35.466911 ], [ -114.665988, 35.467985 ], [ -114.667389, 35.469904 ], [ -114.67235, 35.47374 ], [ -114.673164, 35.474814 ], [ -114.673585, 35.475843 ], [ -114.673473000000101, 35.476849 ], [ -114.672074, 35.479709 ], [ -114.671794, 35.480806 ], [ -114.671907, 35.482087 ], [ -114.673534, 35.485675 ], [ -114.676815000000104, 35.489787 ], [ -114.6767040000001, 35.491845 ], [ -114.676257, 35.493103 ], [ -114.677743, 35.495182 ], [ -114.678642, 35.497628 ], [ -114.678587, 35.499846 ], [ -114.678892000000104, 35.501276 ], [ -114.67748, 35.510948 ], [ -114.677143, 35.512945 ], [ -114.675685, 35.51563 ], [ -114.672767, 35.518428 ], [ -114.66954, 35.52079 ], [ -114.668586, 35.521225 ], [ -114.666565, 35.520993 ], [ -114.664601000000104, 35.521519 ], [ -114.663983000000101, 35.522161 ], [ -114.661682, 35.526682 ], [ -114.659886, 35.527919 ], [ -114.657753, 35.530741 ], [ -114.657163, 35.532301 ], [ -114.65677, 35.534964 ], [ -114.657809, 35.536963 ], [ -114.660335, 35.540433 ], [ -114.661457, 35.544062 ], [ -114.66157, 35.545692 ], [ -114.66112, 35.549021 ], [ -114.661963, 35.552604 ], [ -114.661963, 35.555887 ], [ -114.663451, 35.559884 ], [ -114.663535, 35.560963 ], [ -114.662805, 35.564268 ], [ -114.6639, 35.56629 ], [ -114.664433000000102, 35.568426 ], [ -114.666231, 35.571642 ], [ -114.668393, 35.574331 ], [ -114.670022, 35.575596 ], [ -114.671567, 35.576217 ], [ -114.674881, 35.578379 ], [ -114.675751, 35.579459 ], [ -114.675667, 35.580033 ], [ -114.670191, 35.583471 ], [ -114.664209, 35.585944 ], [ -114.660558, 35.586583 ], [ -114.659238, 35.587477 ], [ -114.654518, 35.596609 ], [ -114.653900000000107, 35.598491 ], [ -114.653731, 35.600373 ], [ -114.654489, 35.605173 ], [ -114.653618, 35.607192 ], [ -114.653534, 35.609672 ], [ -114.653927, 35.611739 ], [ -114.655219, 35.614059 ], [ -114.657241, 35.617046 ], [ -114.659461, 35.619552 ], [ -114.660641, 35.620334 ], [ -114.663647, 35.620773 ], [ -114.665389, 35.621556 ], [ -114.666682, 35.623073 ], [ -114.668087, 35.627115 ], [ -114.669015000000101, 35.628861 ], [ -114.672134, 35.633365 ], [ -114.675001, 35.638304 ], [ -114.677615, 35.641774 ], [ -114.679415000000105, 35.643429 ], [ -114.686133, 35.647522 ], [ -114.689001, 35.65028 ], [ -114.689507, 35.651429 ], [ -114.689226, 35.652898 ], [ -114.690494000000101, 35.662657 ], [ -114.690214, 35.665159 ], [ -114.686055, 35.670642 ], [ -114.682317, 35.677825 ], [ -114.680827, 35.682255 ], [ -114.680631000000105, 35.684046 ], [ -114.680997000000104, 35.685929 ], [ -114.682657000000106, 35.688571 ], [ -114.691263, 35.693125 ], [ -114.696214, 35.69655 ], [ -114.701416, 35.701084 ], [ -114.703608, 35.703922 ], [ -114.704501, 35.705993 ], [ -114.704959, 35.706366 ], [ -114.704842, 35.706744 ], [ -114.705597, 35.708274 ], [ -114.705347000000103, 35.708344 ], [ -114.705447, 35.711757 ], [ -114.699405, 35.726929 ], [ -114.697859, 35.731657 ], [ -114.69654, 35.738934 ], [ -114.6964, 35.742653 ], [ -114.696655, 35.746143 ], [ -114.697585, 35.748417 ], [ -114.697726, 35.750966 ], [ -114.696854, 35.752756 ], [ -114.696546, 35.754638 ], [ -114.694267, 35.756633 ], [ -114.694717, 35.757897 ], [ -114.69742, 35.760677 ], [ -114.700266, 35.766879 ], [ -114.701027, 35.76968 ], [ -114.70117, 35.774112 ], [ -114.699036000000106, 35.788046 ], [ -114.699318000000105, 35.79048 ], [ -114.703178, 35.794685 ], [ -114.705827, 35.798889 ], [ -114.71149, 35.80438 ], [ -114.712026, 35.805529 ], [ -114.710534, 35.807525 ], [ -114.709324, 35.81005 ], [ -114.70634, 35.812022 ], [ -114.703665, 35.814614 ], [ -114.700654, 35.822004 ], [ -114.697276, 35.826776 ], [ -114.69553, 35.829897 ], [ -114.695277000000104, 35.831091 ], [ -114.695249, 35.832285 ], [ -114.695757, 35.833387 ], [ -114.701478, 35.839316 ], [ -114.702293, 35.840792 ], [ -114.702339, 35.842151 ], [ -114.703527, 35.841845 ], [ -114.704173, 35.842669 ], [ -114.704203000000106, 35.844274 ], [ -114.706288, 35.846218 ], [ -114.706532, 35.849027 ], [ -114.705856, 35.850508 ], [ -114.703599, 35.852595 ], [ -114.701904, 35.853223 ], [ -114.696581, 35.853727 ], [ -114.69437, 35.854463 ], [ -114.693446, 35.855125 ], [ -114.691456, 35.858661 ], [ -114.6877980000001, 35.860728 ], [ -114.68205, 35.86295 ], [ -114.678186, 35.863311 ], [ -114.672289, 35.865011 ], [ -114.66968, 35.865036 ], [ -114.667471000000106, 35.867061 ], [ -114.662623, 35.869213 ], [ -114.661636, 35.870545 ], [ -114.661636, 35.871233 ], [ -114.663214, 35.873692 ], [ -114.668145, 35.875201 ], [ -114.672009, 35.878018 ], [ -114.678972, 35.88551 ], [ -114.693602, 35.895311 ], [ -114.69454, 35.896587 ], [ -114.696064, 35.896464 ], [ -114.694928, 35.897594 ], [ -114.696132000000105, 35.898662 ], [ -114.697558, 35.89936 ], [ -114.700258000000105, 35.901757 ], [ -114.700769, 35.903064 ], [ -114.703538, 35.906707 ], [ -114.705119, 35.907637 ], [ -114.705991, 35.908598 ], [ -114.7057140000001, 35.909316 ], [ -114.706767, 35.90895 ], [ -114.708112, 35.909933 ], [ -114.709187, 35.916827 ], [ -114.707784, 35.916993 ], [ -114.707398, 35.918057 ], [ -114.70788, 35.919207 ], [ -114.707329000000101, 35.926177 ], [ -114.707603, 35.92795 ], [ -114.712965, 35.932159 ], [ -114.712756, 35.932639 ], [ -114.713413, 35.9319 ], [ -114.713312, 35.933844 ], [ -114.729762, 35.959895 ], [ -114.728496000000106, 35.960395 ], [ -114.728666, 35.961757 ], [ -114.730090000000104, 35.962691 ], [ -114.732456, 35.965891 ], [ -114.736195, 35.969421 ], [ -114.740536, 35.975545 ], [ -114.743494, 35.983553 ], [ -114.743638, 35.985785 ], [ -114.743117, 35.987387 ], [ -114.740043, 35.990534 ], [ -114.739318, 35.991804 ], [ -114.740544, 35.994853 ], [ -114.740815, 35.997464 ], [ -114.741536, 35.99969 ], [ -114.741679, 36.002283 ], [ -114.743163, 36.006722 ], [ -114.743005, 36.00845 ], [ -114.740866, 36.012928 ], [ -114.738555, 36.015223 ], [ -114.728874000000104, 36.021387 ], [ -114.723324, 36.026588 ], [ -114.722214, 36.027964 ], [ -114.722096, 36.028952 ], [ -114.722742, 36.030286 ], [ -114.723673, 36.03123 ], [ -114.727602, 36.033099 ], [ -114.730563, 36.036207 ], [ -114.733417000000102, 36.037913 ], [ -114.735739, 36.038033 ], [ -114.740018, 36.037467 ], [ -114.741262000000106, 36.038044 ], [ -114.742105, 36.039792 ], [ -114.742661, 36.042573 ], [ -114.742479, 36.045697 ], [ -114.741677, 36.047877 ], [ -114.735701, 36.053393 ], [ -114.73508, 36.054435 ], [ -114.735285, 36.056648 ], [ -114.736023000000102, 36.059063 ], [ -114.74006, 36.062437 ], [ -114.7422, 36.067833 ], [ -114.742138, 36.068676 ], [ -114.743542, 36.071037 ], [ -114.748891, 36.074981 ], [ -114.75057, 36.08033 ], [ -114.754032, 36.083093 ], [ -114.754681, 36.085052 ], [ -114.754508, 36.086171 ], [ -114.752836, 36.089393 ], [ -114.750095, 36.092275 ], [ -114.748913000000101, 36.095183 ], [ -114.737497000000104, 36.103102 ], [ -114.734857, 36.104426 ], [ -114.718257, 36.107164 ], [ -114.709269, 36.107396 ], [ -114.706091, 36.108239 ], [ -114.703737, 36.108348 ], [ -114.696981, 36.110297 ], [ -114.693655000000106, 36.112482 ], [ -114.691631, 36.112535 ], [ -114.6880740000001, 36.111457 ], [ -114.684426000000101, 36.109472 ], [ -114.681847000000104, 36.109192 ], [ -114.679775000000106, 36.109874 ], [ -114.678375, 36.110815 ], [ -114.675106, 36.114111 ], [ -114.671867, 36.115964 ], [ -114.664343000000102, 36.1163 ], [ -114.662144, 36.117742 ], [ -114.660448, 36.119999 ], [ -114.658131, 36.124127 ], [ -114.655512, 36.126187 ], [ -114.645728, 36.131995 ], [ -114.641976, 36.13373 ], [ -114.640125, 36.135126 ], [ -114.636862, 36.135552 ], [ -114.635809, 36.13617 ], [ -114.630474, 36.142218 ], [ -114.628462, 36.141822 ], [ -114.627079, 36.140761 ], [ -114.623837, 36.137144 ], [ -114.620605, 36.131759 ], [ -114.618429, 36.130328 ], [ -114.615455, 36.129653 ], [ -114.61324, 36.130266 ], [ -114.609288, 36.132229 ], [ -114.596474, 36.141537 ], [ -114.5930350000001, 36.142674 ], [ -114.589828, 36.143192 ], [ -114.583716, 36.14556 ], [ -114.580707, 36.145987 ], [ -114.578828, 36.147175 ], [ -114.57706, 36.148845 ], [ -114.57109, 36.151099 ], [ -114.561173, 36.150921 ], [ -114.556162, 36.15247 ], [ -114.548742000000104, 36.150697 ], [ -114.543232, 36.151871 ], [ -114.539233, 36.151764 ], [ -114.534478, 36.15023 ], [ -114.532924, 36.149282 ], [ -114.532308, 36.14804 ], [ -114.531091, 36.147644 ], [ -114.52621, 36.148177 ], [ -114.51428, 36.150795 ], [ -114.511218, 36.150576 ], [ -114.508104000000102, 36.149713 ], [ -114.501049, 36.144516 ], [ -114.500236, 36.143226 ], [ -114.499992, 36.141594 ], [ -114.500339, 36.1407 ], [ -114.50108, 36.14006 ], [ -114.50515, 36.138078 ], [ -114.507175, 36.13634 ], [ -114.50921, 36.133247 ], [ -114.508467, 36.129913 ], [ -114.507201, 36.128484 ], [ -114.504715, 36.127188 ], [ -114.501798, 36.126556 ], [ -114.498849, 36.126612 ], [ -114.487635, 36.128656 ], [ -114.483827, 36.12972 ], [ -114.478248, 36.132683 ], [ -114.468674, 36.138889 ], [ -114.465579, 36.139496 ], [ -114.4626, 36.139644 ], [ -114.458945, 36.139214 ], [ -114.456487, 36.138032 ], [ -114.45511, 36.136372 ], [ -114.453798, 36.133586 ], [ -114.451331, 36.129831 ], [ -114.447135, 36.126022 ], [ -114.445042, 36.125346 ], [ -114.443736, 36.125593 ], [ -114.435507, 36.130057 ], [ -114.423114, 36.13735 ], [ -114.418193, 36.142771 ], [ -114.415253, 36.145123 ], [ -114.412491000000102, 36.146511 ], [ -114.40914, 36.147 ], [ -114.405624, 36.146983 ], [ -114.398373, 36.145799 ], [ -114.381479, 36.141349 ], [ -114.379976, 36.141388 ], [ -114.375278, 36.143592 ], [ -114.373745, 36.143722 ], [ -114.370181, 36.142624 ], [ -114.368551, 36.140892 ], [ -114.367381, 36.13852 ], [ -114.365529, 36.136306 ], [ -114.364499, 36.134072 ], [ -114.358968, 36.127795 ], [ -114.348592, 36.121147 ], [ -114.3451, 36.118556 ], [ -114.342601, 36.115878 ], [ -114.34095, 36.113457 ], [ -114.338815, 36.111309 ], [ -114.337264, 36.110428 ], [ -114.334632, 36.106784 ], [ -114.333587, 36.106342 ], [ -114.328801, 36.105902 ], [ -114.325814, 36.103933 ], [ -114.325539, 36.102989 ], [ -114.323458000000102, 36.101186 ], [ -114.320866, 36.096463 ], [ -114.316983, 36.093409 ], [ -114.313086, 36.088816 ], [ -114.306939, 36.082487 ], [ -114.304171, 36.07558 ], [ -114.304384, 36.074019 ], [ -114.305853, 36.071478 ], [ -114.307485, 36.069672 ], [ -114.31242, 36.066117 ], [ -114.3136, 36.064148 ], [ -114.314328, 36.062016 ], [ -114.314427, 36.060523 ], [ -114.313591, 36.059048 ], [ -114.311904, 36.057661 ], [ -114.308624, 36.056976 ], [ -114.300971000000104, 36.05746 ], [ -114.298593, 36.057263 ], [ -114.295941, 36.056168 ], [ -114.293435000000102, 36.0545 ], [ -114.290867, 36.050511 ], [ -114.287992, 36.04907 ], [ -114.284006, 36.048242 ], [ -114.279637, 36.046103 ], [ -114.278166, 36.045819 ], [ -114.273911, 36.046529 ], [ -114.272299, 36.046289 ], [ -114.270862, 36.045523 ], [ -114.269548, 36.043769 ], [ -114.268896, 36.04094 ], [ -114.26922, 36.036807 ], [ -114.268586, 36.035034 ], [ -114.26438, 36.027911 ], [ -114.262388, 36.026107 ], [ -114.259518, 36.024206 ], [ -114.251633, 36.019886 ], [ -114.248419, 36.018556 ], [ -114.246111, 36.017164 ], [ -114.243865, 36.015266 ], [ -114.240439, 36.015245 ], [ -114.238154, 36.014473 ], [ -114.236892, 36.013247 ], [ -114.233443, 36.012835 ], [ -114.231854, 36.013147 ], [ -114.228015, 36.014731 ], [ -114.226459, 36.014606 ], [ -114.224798, 36.013699 ], [ -114.218759, 36.014511 ], [ -114.216609, 36.014336 ], [ -114.214679, 36.014806 ], [ -114.213549, 36.014615 ], [ -114.211932, 36.014834 ], [ -114.206052, 36.016634 ], [ -114.204156, 36.016575 ], [ -114.201227, 36.017751 ], [ -114.200066, 36.017743 ], [ -114.191221, 36.020019 ], [ -114.185860000000105, 36.022266 ], [ -114.179438, 36.024313 ], [ -114.176304, 36.026129 ], [ -114.174683, 36.02667 ], [ -114.164402, 36.026852 ], [ -114.161237, 36.026279 ], [ -114.157344, 36.024966 ], [ -114.1534, 36.02317 ], [ -114.15139, 36.023133 ], [ -114.150225, 36.023515 ], [ -114.145907, 36.027229 ], [ -114.145637, 36.028559 ], [ -114.145672, 36.03297 ], [ -114.144666, 36.034272 ], [ -114.143153, 36.035295 ], [ -114.13826, 36.03719 ], [ -114.137112, 36.038491 ], [ -114.135721, 36.041238 ], [ -114.134841, 36.043873 ], [ -114.134824, 36.045343 ], [ -114.135927, 36.050358 ], [ -114.136206, 36.053232 ], [ -114.1352, 36.056946 ], [ -114.133389, 36.061665 ], [ -114.129768, 36.068484 ], [ -114.125891, 36.072935 ], [ -114.124019, 36.075563 ], [ -114.121186, 36.082755 ], [ -114.119648, 36.085822 ], [ -114.112297, 36.09405 ], [ -114.111998, 36.09491 ], [ -114.1119, 36.095845 ], [ -114.115208, 36.099878 ], [ -114.11707, 36.101177 ], [ -114.119329, 36.10193 ], [ -114.121033, 36.103885 ], [ -114.121779, 36.105699 ], [ -114.12167, 36.108294 ], [ -114.120865, 36.11085 ], [ -114.118497, 36.1139 ], [ -114.116061, 36.115471 ], [ -114.108381, 36.119154 ], [ -114.107419, 36.119401 ], [ -114.100433, 36.119359 ], [ -114.097707, 36.120213 ], [ -114.096994, 36.120823 ], [ -114.092753, 36.132356 ], [ -114.092366, 36.135331 ], [ -114.091701, 36.137303 ], [ -114.089279, 36.140326 ], [ -114.087899, 36.142923 ], [ -114.081234, 36.150208 ], [ -114.07945, 36.154625 ], [ -114.078832, 36.157434 ], [ -114.075641, 36.162523 ], [ -114.071652, 36.170921 ], [ -114.066798, 36.179087 ], [ -114.058662, 36.187835 ], [ -114.052743, 36.190919 ], [ -114.049484, 36.192134 ], [ -114.043944, 36.19335 ], [ -114.043849, 36.245114 ], [ -114.045518, 36.27439 ], [ -114.045559, 36.288837 ], [ -114.045033, 36.30305 ], [ -114.044345, 36.310234 ], [ -114.044051, 36.317628 ], [ -114.044776, 36.331969 ], [ -114.044702, 36.346298 ], [ -114.043034, 36.38587 ], [ -114.042843000000104, 36.448175 ], [ -114.043133, 36.469716 ], [ -114.044816, 36.491343 ], [ -114.045647, 36.521095 ], [ -114.04632, 36.564615 ], [ -114.049935, 36.709521 ], [ -114.049973, 36.738672 ], [ -114.050327, 36.752899 ], [ -114.049879, 36.781909 ], [ -114.050502, 36.895232 ], [ -114.049995, 36.957769 ], [ -114.050600000000102, 37.000396 ], [ -114.0008, 37.000448 ], [ -113.96266, 36.999973 ], [ -113.052912, 36.999983 ], [ -112.875756, 37.000533 ], [ -112.538546, 37.000652 ], [ -112.529846, 37.000899 ], [ -112.36102, 37.001114 ], [ -112.36037, 37.000912 ], [ -112.359329, 37.001117 ], [ -112.125741, 37.001237 ], [ -112.000735, 37.000959 ], [ -111.62572, 37.001401 ], [ -111.616249, 37.001647 ], [ -111.406146, 37.001481 ], [ -111.405895, 37.001702 ], [ -111.313211, 37.000894 ], [ -111.312169, 37.001193 ], [ -111.305843, 37.000776 ], [ -111.278221, 37.000467 ], [ -111.254853, 37.001076 ], [ -111.133718, 37.000779 ], [ -111.081493, 37.002261 ], [ -111.052354, 37.00246 ], [ -111.00182, 37.002293 ], [ -110.625691, 37.003725 ], [ -110.625605, 37.003416 ], [ -110.599512, 37.003448 ], [ -110.509004, 37.003985 ], [ -110.50069, 37.00426 ], [ -110.490908, 37.003566 ], [ -110.478446, 36.999996 ], [ -110.47729, 36.999997 ], [ -110.47019, 36.997997 ], [ -110.023043, 36.998601 ], [ -110.000876, 36.998502 ], [ -110.000677, 36.997968 ], [ -109.969958, 36.997949 ], [ -109.938511, 36.998491 ], [ -109.750669, 36.99816 ], [ -109.743284, 36.998453 ], [ -109.625658, 36.998308 ], [ -109.495338, 36.999105 ], [ -109.362565, 36.999304 ], [ -109.125691, 36.999389 ], [ -109.045223, 36.999084 ], [ -109.045554, 36.645013 ], [ -109.04539, 36.503241 ], [ -109.045946, 36.375002 ], [ -109.045637, 36.374625 ], [ -109.045744, 36.257214 ], [ -109.046024, 36.247197 ], [ -109.045877, 36.188719 ], [ -109.046183, 36.181751 ], [ -109.045726, 36.116908 ], [ -109.045767, 36.033679 ], [ -109.046124, 35.990618 ], [ -109.046009, 35.875012 ], [ -109.046423, 35.624911 ], [ -109.046181, 35.614569 ], [ -109.046795, 35.379918 ], [ -109.046084, 35.249986 ], [ -109.046256, 35.125041 ], [ -109.045842, 34.966076 ], [ -109.046136, 34.875006 ], [ -109.046072, 34.828566 ], [ -109.045626, 34.814226 ], [ -109.046104, 34.799981 ], [ -109.045363, 34.785406 ], [ -109.046087, 34.770963 ], [ -109.046175, 34.520102 ], [ -109.046561, 34.379479 ], [ -109.046337, 34.283639 ], [ -109.046664, 34.250046 ], [ -109.04696, 34.068968 ], [ -109.047006, 34.00005 ], [ -109.046426, 33.875052 ], [ -109.046869, 33.844183 ], [ -109.047145, 33.74001 ], [ -109.046662, 33.625055 ], [ -109.046825, 33.469389 ], [ -109.047309, 33.462131 ], [ -109.046928, 33.4428 ], [ -109.047304, 33.439442 ], [ -109.047298, 33.409774 ], [ -109.046564, 33.375059 ], [ -109.047045, 33.36928 ], [ -109.046827, 33.365271 ], [ -109.047104, 33.27046 ], [ -109.04747, 33.250168 ], [ -109.047122, 33.2408 ], [ -109.047324, 33.18408 ], [ -109.047208, 33.107377 ], [ -109.046905, 33.091931 ], [ -109.047513, 33.059137 ], [ -109.047382, 33.000311 ], [ -109.04711, 32.99225 ], [ -109.047117, 32.777569 ], [ -109.047518, 32.749997 ], [ -109.047796, 32.68263 ], [ -109.047912, 32.500261 ], [ -109.047629, 32.413987 ], [ -109.048323, 32.070887 ], [ -109.048731, 32.028174 ], [ -109.048465, 32.000089 ], [ -109.048738, 31.876905 ], [ -109.049048, 31.870689 ], [ -109.049298, 31.796742 ], [ -109.04899, 31.721922 ], [ -109.049311, 31.544932 ], [ -109.050173, 31.480004 ], [ -109.049934, 31.437907 ], [ -109.050044, 31.332502 ], [ -109.1256, 31.332685 ], [ -109.271744, 31.333942 ], [ -109.49449, 31.334125 ], [ -109.500621, 31.333911 ], [ -109.875628, 31.33405 ], [ -110.000613, 31.333145 ], [ -110.140512, 31.333965 ], [ -110.375635, 31.332896 ], [ -110.460172, 31.332827 ], [ -110.68143, 31.33309 ], [ -110.750638, 31.333636 ], [ -110.795467, 31.33363 ], [ -110.94232, 31.332833 ], [ -111.000643, 31.332177 ], [ -111.074825, 31.332239 ], [ -111.125646, 31.348978 ], [ -111.129451, 31.349979 ], [ -111.357436, 31.423346 ], [ -111.500659, 31.468862 ], [ -111.560194, 31.488138 ], [ -111.659998, 31.519448 ], [ -111.738873, 31.544718 ], [ -111.875674, 31.587657 ], [ -111.979304, 31.620648 ], [ -112.200717, 31.690033 ], [ -112.365328, 31.741078 ], [ -112.375759, 31.743987 ], [ -112.399254, 31.751638 ], [ -112.433246, 31.762162 ], [ -112.737399, 31.855527 ], [ -112.800213, 31.87507 ], [ -112.834233, 31.885137 ], [ -112.871505, 31.896838 ], [ -113.125961, 31.97278 ], [ -113.21163, 32.000061 ], [ -113.211365, 32.000061 ], [ -113.217307, 32.002106 ], [ -113.250731, 32.012405 ], [ -113.493196, 32.088943 ], [ -113.750756, 32.169005 ], [ -113.78168, 32.179034 ], [ -114.250775, 32.323909 ], [ -114.625785, 32.43789 ], [ -114.790245, 32.487505 ], [ -114.813613, 32.494276 ], [ -114.813991000000101, 32.497231 ], [ -114.812316, 32.500054 ], [ -114.813402, 32.501764 ], [ -114.813753000000105, 32.50426 ], [ -114.815185, 32.506023 ], [ -114.81651, 32.506963 ], [ -114.816591000000102, 32.507696 ], [ -114.815591, 32.508612 ], [ -114.814321000000106, 32.509023 ], [ -114.812942, 32.509116 ], [ -114.810159, 32.508383 ], [ -114.807726, 32.508726 ], [ -114.804076, 32.510375 ], [ -114.802833, 32.511749 ], [ -114.802211, 32.513191 ], [ -114.802238, 32.515206 ], [ -114.80367, 32.516374 ], [ -114.807753, 32.516925 ], [ -114.809672, 32.517567 ], [ -114.810374, 32.518391 ], [ -114.809969, 32.520291 ], [ -114.810482, 32.521758 ], [ -114.810969, 32.522444 ], [ -114.812888, 32.52359 ], [ -114.813348000000104, 32.524186 ], [ -114.812645, 32.525399 ], [ -114.811293, 32.526429 ], [ -114.810563, 32.527666 ], [ -114.808617, 32.529017 ], [ -114.80640000000011, 32.531191 ], [ -114.804858, 32.533689 ], [ -114.802559, 32.535521 ], [ -114.802181, 32.536414 ], [ -114.802018, 32.53946 ], [ -114.80237, 32.540078 ], [ -114.804776000000103, 32.541659 ], [ -114.805966, 32.545346 ], [ -114.8058300000001, 32.546354 ], [ -114.803883, 32.548001 ], [ -114.795635, 32.550956 ], [ -114.793769, 32.552329 ], [ -114.792065, 32.555009 ], [ -114.791551, 32.557023 ], [ -114.791523, 32.558602 ], [ -114.792955000000106, 32.562085 ], [ -114.792088, 32.568497 ], [ -114.792358000000107, 32.569091 ], [ -114.793224, 32.569459 ], [ -114.794684, 32.568703 ], [ -114.795253, 32.56662 ], [ -114.79766, 32.564444 ], [ -114.801311, 32.562865 ], [ -114.803664, 32.560689 ], [ -114.806830000000105, 32.55888 ], [ -114.808885, 32.558467 ], [ -114.810318, 32.558628 ], [ -114.812914, 32.560049 ], [ -114.813995, 32.562201 ], [ -114.814212, 32.56369 ], [ -114.813968, 32.566209 ], [ -114.812995, 32.568706 ], [ -114.81148, 32.569781 ], [ -114.804421, 32.572941 ], [ -114.803474, 32.573628 ], [ -114.801877, 32.576009 ], [ -114.801471, 32.578255 ], [ -114.80193, 32.579194 ], [ -114.803879, 32.580889 ], [ -114.803987, 32.582652 ], [ -114.802823, 32.585079 ], [ -114.800441, 32.588079 ], [ -114.799737, 32.592177 ], [ -114.799683, 32.593621 ], [ -114.801251, 32.596232 ], [ -114.801548, 32.598591 ], [ -114.802361, 32.59937 ], [ -114.805932, 32.600721 ], [ -114.8069050000001, 32.60143 ], [ -114.808041, 32.603172 ], [ -114.807879, 32.605416 ], [ -114.809042, 32.608806 ], [ -114.808906, 32.612951 ], [ -114.809555, 32.616203 ], [ -114.808662, 32.619157 ], [ -114.80739, 32.621332 ], [ -114.806821, 32.621721 ], [ -114.799302, 32.625115 ], [ -114.797564, 32.624578 ], [ -114.794102, 32.622475 ], [ -114.792640000000105, 32.621948 ], [ -114.791179, 32.621833 ], [ -114.787715, 32.623573 ], [ -114.782573, 32.624304 ], [ -114.781896, 32.624702 ], [ -114.781766, 32.625613 ], [ -114.782518, 32.628625 ], [ -114.782235, 32.630215 ], [ -114.779215, 32.633578 ], [ -114.77457, 32.63593 ], [ -114.771978, 32.637954 ], [ -114.768199, 32.639874 ], [ -114.764382, 32.642666 ], [ -114.76331, 32.644616 ], [ -114.763512, 32.645995 ], [ -114.764917, 32.648079 ], [ -114.76495, 32.649391 ], [ -114.75831, 32.655178 ], [ -114.751079, 32.659789 ], [ -114.749480000000105, 32.66178 ], [ -114.748000000000104, 32.664184 ], [ -114.748183, 32.665098 ], [ -114.747817, 32.667777 ], [ -114.746383, 32.669853 ], [ -114.745344, 32.67219 ], [ -114.7449, 32.677231 ], [ -114.744349, 32.678935 ], [ -114.740541, 32.684196 ], [ -114.739405, 32.686385 ], [ -114.730453, 32.698844 ], [ -114.72981, 32.700282 ], [ -114.72974, 32.703121 ], [ -114.730086, 32.704298 ], [ -114.728408, 32.706648 ], [ -114.726974, 32.707875 ], [ -114.72534, 32.710369 ], [ -114.72241, 32.713597 ], [ -114.719938, 32.71829 ], [ -114.717695, 32.721547 ], [ -114.715788, 32.727758 ], [ -114.714522, 32.73039 ], [ -114.712629, 32.732678 ], [ -114.710615, 32.733936 ], [ -114.709074, 32.735456 ], [ -114.706114, 32.740986 ], [ -114.70294, 32.744793 ], [ -114.701582000000101, 32.745632 ], [ -114.699247, 32.745098 ], [ -114.695387, 32.742244 ], [ -114.691801, 32.740147 ], [ -114.689282, 32.737927 ], [ -114.688230000000104, 32.73753 ], [ -114.682614, 32.737348 ], [ -114.672025, 32.734951 ], [ -114.665921, 32.734028 ], [ -114.654247, 32.73357 ], [ -114.645353, 32.732139 ], [ -114.635006000000104, 32.731372 ], [ -114.629299, 32.729908 ], [ -114.617479, 32.728243 ], [ -114.61567, 32.728454 ], [ -114.61587, 32.729717 ], [ -114.615501, 32.730044 ], [ -114.615504, 32.731449 ], [ -114.614786, 32.732846 ], [ -114.614787000000106, 32.734076 ], [ -114.615112, 32.734515 ], [ -114.581784, 32.734946 ], [ -114.581736, 32.74232 ], [ -114.564508, 32.742274 ], [ -114.564447, 32.749554 ], [ -114.539224, 32.749812 ], [ -114.539092, 32.756949 ], [ -114.526856, 32.757094 ], [ -114.528443, 32.767276 ], [ -114.529264, 32.769484 ], [ -114.531831, 32.774264 ], [ -114.532432, 32.776922 ], [ -114.532426, 32.778644 ], [ -114.531746, 32.782503 ], [ -114.531669, 32.791185 ], [ -114.529633000000103, 32.795477 ], [ -114.522031, 32.801675 ], [ -114.520385, 32.803576 ], [ -114.520363000000103, 32.804385 ], [ -114.519758, 32.805676 ], [ -114.515389, 32.811439 ], [ -114.510327, 32.816488 ], [ -114.494116, 32.823287 ], [ -114.475892, 32.838693 ], [ -114.468971, 32.845155 ], [ -114.465711, 32.873681 ], [ -114.465172, 32.885295 ], [ -114.463307, 32.899116 ], [ -114.462929, 32.907944 ], [ -114.46365, 32.911682 ], [ -114.464448, 32.913128 ], [ -114.473713, 32.920594 ], [ -114.47664, 32.923628 ], [ -114.477952000000101, 32.925706 ], [ -114.479005, 32.928291 ], [ -114.480783, 32.933678 ], [ -114.480925, 32.936276 ], [ -114.48074, 32.937027 ], [ -114.478456, 32.940555 ], [ -114.474042, 32.94515 ], [ -114.470768, 32.949424 ], [ -114.468536, 32.953922 ], [ -114.467624, 32.956663 ], [ -114.467274, 32.960172 ], [ -114.467367, 32.965384 ], [ -114.468379, 32.970745 ], [ -114.468995, 32.972239 ], [ -114.470511, 32.973858 ], [ -114.472606, 32.974654 ], [ -114.475171, 32.975154 ], [ -114.477308, 32.975023 ], [ -114.479477, 32.974189 ], [ -114.480831, 32.973362 ], [ -114.481315, 32.972064 ], [ -114.484806, 32.971339 ], [ -114.488625, 32.969946 ], [ -114.490129, 32.969884 ], [ -114.492184, 32.971021 ], [ -114.492938, 32.971781 ], [ -114.494212, 32.974262 ], [ -114.495712, 32.980075 ], [ -114.496798, 32.986534 ], [ -114.497052, 32.990206 ], [ -114.49941, 33.00004 ], [ -114.499797, 33.003905 ], [ -114.50287, 33.011154 ], [ -114.506129, 33.017009 ], [ -114.507956, 33.019708 ], [ -114.511343, 33.023455 ], [ -114.5149, 33.026524 ], [ -114.52013, 33.029984 ], [ -114.523578, 33.03096 ], [ -114.538459, 33.033422 ], [ -114.553189, 33.033974 ], [ -114.56085, 33.035285 ], [ -114.5648, 33.035077 ], [ -114.571653, 33.036624 ], [ -114.575161, 33.036541 ], [ -114.578287, 33.035375 ], [ -114.581404, 33.032545 ], [ -114.584765, 33.02823 ], [ -114.586982, 33.026944 ], [ -114.589778, 33.026228 ], [ -114.598093, 33.025384 ], [ -114.601014, 33.02541 ], [ -114.611584, 33.026221 ], [ -114.618788, 33.027202 ], [ -114.625787, 33.029435 ], [ -114.628294, 33.03105 ], [ -114.629732, 33.032546 ], [ -114.63419, 33.039024 ], [ -114.639552, 33.04529 ], [ -114.641621, 33.046894 ], [ -114.64482, 33.048644 ], [ -114.645979, 33.048902 ], [ -114.647049, 33.048416 ], [ -114.649001, 33.046762 ], [ -114.650999, 33.044131 ], [ -114.655038000000104, 33.037106 ], [ -114.657827, 33.033824 ], [ -114.659832, 33.032664 ], [ -114.662317, 33.03267 ], [ -114.66506, 33.033906 ], [ -114.670803, 33.037983 ], [ -114.673659, 33.041896 ], [ -114.67483, 33.045507 ], [ -114.675103000000107, 33.04753 ], [ -114.674295, 33.057169 ], [ -114.679114, 33.061966 ], [ -114.686991, 33.070968 ], [ -114.68912, 33.076121 ], [ -114.689307, 33.079179 ], [ -114.688597000000101, 33.082869 ], [ -114.68902, 33.084035 ], [ -114.692548000000102, 33.085786 ], [ -114.694628, 33.086226 ], [ -114.701165000000103, 33.086368 ], [ -114.70473, 33.087051 ], [ -114.706488, 33.08816 ], [ -114.707819, 33.091102 ], [ -114.708133000000103, 33.094022 ], [ -114.707896000000105, 33.097431 ], [ -114.706175, 33.105334 ], [ -114.703682, 33.113768 ], [ -114.696914, 33.131119 ], [ -114.694858, 33.13346 ], [ -114.690246, 33.137724 ], [ -114.687405, 33.141983 ], [ -114.684907, 33.147823 ], [ -114.682759, 33.154808 ], [ -114.679945, 33.159059 ], [ -114.67935, 33.162433 ], [ -114.68089, 33.169074 ], [ -114.680237, 33.169637 ], [ -114.679115, 33.174608 ], [ -114.675830000000104, 33.18152 ], [ -114.6753590000001, 33.185488 ], [ -114.675189, 33.188178 ], [ -114.678163, 33.199488 ], [ -114.678749, 33.203448 ], [ -114.676072, 33.210835 ], [ -114.673715, 33.219245 ], [ -114.673626, 33.223121 ], [ -114.674479000000105, 33.225504 ], [ -114.678097, 33.2303 ], [ -114.682731, 33.234918 ], [ -114.689421, 33.24525 ], [ -114.689541, 33.246428 ], [ -114.688205, 33.247965 ], [ -114.683253, 33.250034 ], [ -114.67766, 33.254426 ], [ -114.674491000000103, 33.255597 ], [ -114.672924, 33.257042 ], [ -114.672088, 33.258499 ], [ -114.672401, 33.260469 ], [ -114.677032, 33.270169 ], [ -114.680507, 33.273576 ], [ -114.684363000000104, 33.276023 ], [ -114.688599, 33.277861 ], [ -114.694449, 33.279785 ], [ -114.702873, 33.281916 ], [ -114.711197, 33.283341 ], [ -114.717875, 33.285156 ], [ -114.72167, 33.286982 ], [ -114.723259, 33.288079 ], [ -114.731223, 33.302433 ], [ -114.731222000000102, 33.304039 ], [ -114.729904000000104, 33.305745 ], [ -114.726484, 33.308273 ], [ -114.724665000000101, 33.310097 ], [ -114.723623000000103, 33.312109 ], [ -114.71861, 33.315761 ], [ -114.710627, 33.3205 ], [ -114.70787, 33.323316 ], [ -114.705186, 33.327709 ], [ -114.700938, 33.337014 ], [ -114.69935, 33.345692 ], [ -114.699124, 33.349258 ], [ -114.698035, 33.352442 ], [ -114.69817, 33.356575 ], [ -114.699056, 33.361148 ], [ -114.701959, 33.367134 ], [ -114.704201, 33.371238 ], [ -114.706722, 33.37503 ], [ -114.707348, 33.376627 ], [ -114.707485000000105, 33.378375 ], [ -114.707009, 33.380633 ], [ -114.707309, 33.38254 ], [ -114.708407, 33.384142 ], [ -114.713602, 33.388256 ], [ -114.72425, 33.40042 ], [ -114.725292, 33.402341 ], [ -114.725535, 33.404055 ], [ -114.725282, 33.405048 ], [ -114.723829, 33.406531 ], [ -114.722201, 33.407384 ], [ -114.720065000000105, 33.407891 ], [ -114.710878, 33.407254 ], [ -114.701788, 33.408377 ], [ -114.697708, 33.410942 ], [ -114.696805, 33.412087 ], [ -114.696507, 33.414063 ], [ -114.695658, 33.415128 ], [ -114.68795, 33.417934 ], [ -114.673691, 33.419157 ], [ -114.658254, 33.413021 ], [ -114.656735, 33.412813 ], [ -114.652828, 33.412923 ], [ -114.64954, 33.413633 ], [ -114.643302, 33.416746 ], [ -114.635183, 33.422725 ], [ -114.633262, 33.425024 ], [ -114.630903, 33.426754 ], [ -114.62964, 33.428137 ], [ -114.627479, 33.432307 ], [ -114.622283, 33.447558 ], [ -114.622519, 33.450879 ], [ -114.623395000000102, 33.45449 ], [ -114.622918, 33.456561 ], [ -114.618354, 33.462708 ], [ -114.614331, 33.467315 ], [ -114.6137820000001, 33.469049 ], [ -114.612472, 33.470768 ], [ -114.607843000000102, 33.474834 ], [ -114.603396000000103, 33.480631 ], [ -114.601694, 33.481396 ], [ -114.599712, 33.484316 ], [ -114.597283000000104, 33.490653 ], [ -114.593721, 33.495932 ], [ -114.592369, 33.498675 ], [ -114.589246, 33.501813 ], [ -114.580468, 33.506465 ], [ -114.573757, 33.507543 ], [ -114.569533, 33.509219 ], [ -114.560963, 33.516739 ], [ -114.560552, 33.518272 ], [ -114.560835, 33.524334 ], [ -114.560098, 33.526663 ], [ -114.559507, 33.530724 ], [ -114.558898, 33.531819 ], [ -114.542011, 33.542481 ], [ -114.531802, 33.547862 ], [ -114.530401, 33.550099 ], [ -114.525997000000103, 33.551457 ], [ -114.524599, 33.552231 ], [ -114.524215, 33.553068 ], [ -114.52822, 33.559318 ], [ -114.531613, 33.561702 ], [ -114.532333, 33.562879 ], [ -114.533192, 33.565823 ], [ -114.535965000000104, 33.569154 ], [ -114.536784, 33.570959 ], [ -114.537801, 33.575555 ], [ -114.538983, 33.576792 ], [ -114.5403, 33.580615 ], [ -114.540652, 33.582872 ], [ -114.540111, 33.588354 ], [ -114.540664, 33.589789 ], [ -114.540617, 33.591412 ], [ -114.537493, 33.594895 ], [ -114.536777, 33.596394 ], [ -114.531051, 33.604482 ], [ -114.529186, 33.60665 ], [ -114.526782, 33.608831 ], [ -114.523994, 33.60999 ], [ -114.522071, 33.611277 ], [ -114.521845, 33.612544 ], [ -114.522367, 33.614172 ], [ -114.527378, 33.617828 ], [ -114.528578, 33.619994 ], [ -114.52908, 33.621711 ], [ -114.531215, 33.623913 ], [ -114.531034, 33.628213 ], [ -114.530311, 33.629037 ], [ -114.52637, 33.630259 ], [ -114.523802, 33.6347 ], [ -114.525394, 33.640669 ], [ -114.529549000000102, 33.643861 ], [ -114.533215, 33.648443 ], [ -114.533194, 33.65166 ], [ -114.532164, 33.653194 ], [ -114.530583, 33.654461 ], [ -114.525163, 33.655939 ], [ -114.518337, 33.655927 ], [ -114.514559000000105, 33.658014 ], [ -114.514057, 33.660179 ], [ -114.515336, 33.662033 ], [ -114.517112, 33.662877 ], [ -114.520671, 33.662681 ], [ -114.526439, 33.66388 ], [ -114.530267, 33.666821 ], [ -114.532123, 33.669702 ], [ -114.531523, 33.675108 ], [ -114.530348, 33.679245 ], [ -114.527782, 33.682684 ], [ -114.523959, 33.685879 ], [ -114.519113, 33.688473 ], [ -114.512409, 33.691282 ], [ -114.507996, 33.692018 ], [ -114.504993, 33.693022 ], [ -114.502899, 33.694255 ], [ -114.496489, 33.696901 ], [ -114.495719, 33.698454 ], [ -114.495537, 33.701506 ], [ -114.494407, 33.705395 ], [ -114.494197, 33.707922 ], [ -114.494901, 33.71443 ], [ -114.496565, 33.719155 ], [ -114.498133, 33.720634 ], [ -114.500788, 33.722204 ], [ -114.502661, 33.724584 ], [ -114.504176, 33.728055 ], [ -114.506799, 33.730518 ], [ -114.510265, 33.732146 ], [ -114.512348000000102, 33.734214 ], [ -114.510777, 33.737574 ], [ -114.508206, 33.741587 ], [ -114.506, 33.746344 ], [ -114.504483, 33.750998 ], [ -114.50434, 33.756381 ], [ -114.504863, 33.760465 ], [ -114.507089, 33.76793 ], [ -114.516734, 33.788345 ], [ -114.518942, 33.797302 ], [ -114.521555, 33.801982 ], [ -114.524682, 33.808961 ], [ -114.527188, 33.812639 ], [ -114.52805, 33.814963 ], [ -114.527886, 33.815617 ], [ -114.527161, 33.816191 ], [ -114.522714, 33.818979 ], [ -114.520733, 33.822031 ], [ -114.51997, 33.825381 ], [ -114.520465, 33.827778 ], [ -114.523409, 33.835323 ], [ -114.525539, 33.838614 ], [ -114.529597, 33.848063 ], [ -114.530607, 33.85544 ], [ -114.529883, 33.857563 ], [ -114.527069, 33.859429 ], [ -114.525666, 33.860003 ], [ -114.524292, 33.860133 ], [ -114.52287, 33.859965 ], [ -114.518998, 33.858563 ], [ -114.516811000000104, 33.85812 ], [ -114.514673, 33.858638 ], [ -114.511346, 33.86157 ], [ -114.506635, 33.863484 ], [ -114.505638, 33.864276 ], [ -114.503887, 33.865754 ], [ -114.503104, 33.867166 ], [ -114.503017, 33.867998 ], [ -114.503860000000103, 33.871234 ], [ -114.503395, 33.875018 ], [ -114.50434, 33.876882 ], [ -114.510138, 33.880777 ], [ -114.51866, 33.888263 ], [ -114.522768, 33.892583 ], [ -114.524813, 33.895684 ], [ -114.525872, 33.901008 ], [ -114.52569, 33.901428 ], [ -114.524289, 33.901587 ], [ -114.516344, 33.897918 ], [ -114.513715, 33.897959 ], [ -114.510944, 33.899099 ], [ -114.508708, 33.90064 ], [ -114.507988, 33.901813 ], [ -114.50792, 33.903807 ], [ -114.508558, 33.906098 ], [ -114.511511, 33.911092 ], [ -114.514503, 33.914214 ], [ -114.518434, 33.917518 ], [ -114.523393, 33.921221 ], [ -114.525361, 33.922272 ], [ -114.528385, 33.923674 ], [ -114.531107, 33.924633 ], [ -114.534146, 33.925187 ], [ -114.534951, 33.9257 ], [ -114.535853, 33.928103 ], [ -114.535478, 33.934651 ], [ -114.530566, 33.943629 ], [ -114.52868, 33.947817 ], [ -114.526353, 33.950917 ], [ -114.522002, 33.955623 ], [ -114.51586, 33.958106 ], [ -114.51497, 33.958149 ], [ -114.511231, 33.95704 ], [ -114.509568, 33.957264 ], [ -114.499883, 33.961789 ], [ -114.496042, 33.96589 ], [ -114.490398, 33.97062 ], [ -114.488459, 33.972832 ], [ -114.484784, 33.975519 ], [ -114.483097, 33.977745 ], [ -114.482333, 33.980181 ], [ -114.481455, 33.981261 ], [ -114.475907, 33.984424 ], [ -114.471138, 33.98804 ], [ -114.467932, 33.992877 ], [ -114.466187, 33.993465 ], [ -114.461133, 33.993541 ], [ -114.46012, 33.993888 ], [ -114.459258, 33.994711 ], [ -114.458028, 33.997158 ], [ -114.458026000000103, 33.99782 ], [ -114.459184, 34.000016 ], [ -114.460689, 34.001128 ], [ -114.46628, 34.003885 ], [ -114.46731, 34.00519 ], [ -114.467404, 34.00745 ], [ -114.465867000000102, 34.010987 ], [ -114.464525, 34.011982 ], [ -114.463336, 34.012259 ], [ -114.454807, 34.010968 ], [ -114.450206, 34.012574 ], [ -114.446815, 34.01421 ], [ -114.443821, 34.016176 ], [ -114.44054, 34.019329 ], [ -114.438266, 34.022609 ], [ -114.436171, 34.028083 ], [ -114.434949, 34.037784 ], [ -114.435816, 34.04373 ], [ -114.438602, 34.050205 ], [ -114.439406, 34.05381 ], [ -114.43934, 34.057893 ], [ -114.437683, 34.071937 ], [ -114.435907, 34.077491 ], [ -114.434181, 34.087379 ], [ -114.43338, 34.088413 ], [ -114.428026, 34.092787 ], [ -114.426168, 34.097042 ], [ -114.422899, 34.099661 ], [ -114.420499, 34.103466 ], [ -114.415908, 34.107636 ], [ -114.41168, 34.110031 ], [ -114.405916, 34.111468 ], [ -114.401336, 34.111638 ], [ -114.390565, 34.110084 ], [ -114.379223, 34.11599 ], [ -114.369292000000101, 34.117519 ], [ -114.366517, 34.118577 ], [ -114.360402, 34.123577 ], [ -114.359389, 34.125016 ], [ -114.358358, 34.127617 ], [ -114.356372, 34.130428 ], [ -114.35303, 34.13312 ], [ -114.350478, 34.134107 ], [ -114.348051, 34.134457 ], [ -114.336112, 34.134034 ], [ -114.324576, 34.136759 ], [ -114.320777, 34.138635 ], [ -114.312206, 34.144776 ], [ -114.307802, 34.150574 ], [ -114.298168, 34.160321 ], [ -114.292806, 34.166725 ], [ -114.287294, 34.170529 ], [ -114.275267, 34.172149 ], [ -114.26846, 34.170177 ], [ -114.257034, 34.172837 ], [ -114.253444000000101, 34.174129 ], [ -114.244421, 34.179403 ], [ -114.240712000000102, 34.183232 ], [ -114.229715, 34.186928 ], [ -114.227034, 34.188866 ], [ -114.225814, 34.191238 ], [ -114.224941, 34.193896 ], [ -114.225075, 34.196814 ], [ -114.22579, 34.199236 ], [ -114.225861, 34.201774 ], [ -114.225194, 34.203642 ], [ -114.223384, 34.205136 ], [ -114.215454, 34.208956 ], [ -114.211761, 34.211539 ], [ -114.208253, 34.215505 ], [ -114.190876, 34.230858 ], [ -114.17805, 34.239969 ], [ -114.176403, 34.241512 ], [ -114.175948, 34.242695 ], [ -114.175906, 34.245587 ], [ -114.174597, 34.247303 ], [ -114.166536, 34.249647 ], [ -114.166124, 34.250015 ], [ -114.164476, 34.251667 ], [ -114.163867, 34.253349 ], [ -114.163959, 34.255377 ], [ -114.165335, 34.258486 ], [ -114.165249, 34.259125 ], [ -114.164648, 34.259699 ], [ -114.156853, 34.258415 ], [ -114.153346, 34.258289 ], [ -114.147159, 34.259564 ], [ -114.144779, 34.259623 ], [ -114.13545, 34.257886 ], [ -114.133264, 34.258462 ], [ -114.131489000000101, 34.260387 ], [ -114.131211, 34.26273 ], [ -114.134768, 34.268965 ], [ -114.136671, 34.274377 ], [ -114.137045, 34.277018 ], [ -114.13605, 34.280833 ], [ -114.136677, 34.283936 ], [ -114.138365, 34.288564 ], [ -114.139534, 34.295844 ], [ -114.139187, 34.298074 ], [ -114.138167, 34.300936 ], [ -114.138282, 34.30323 ], [ -114.14093, 34.305919 ], [ -114.157206, 34.317862 ], [ -114.157939, 34.320277 ], [ -114.164249, 34.330816 ], [ -114.168807, 34.339513 ], [ -114.172845, 34.344979 ], [ -114.176909, 34.349306 ], [ -114.181145, 34.352186 ], [ -114.185556, 34.354386 ], [ -114.191094, 34.356125 ], [ -114.19648, 34.359187 ], [ -114.199482, 34.361373 ], [ -114.213774, 34.36246 ], [ -114.226107, 34.365916 ], [ -114.229686, 34.368908 ], [ -114.233065, 34.375013 ], [ -114.234275, 34.376662 ], [ -114.245261, 34.385659 ], [ -114.248649, 34.388113 ], [ -114.252739, 34.3901 ], [ -114.25822, 34.395046 ], [ -114.262909, 34.400373 ], [ -114.264317000000105, 34.401329 ], [ -114.267521, 34.402486 ], [ -114.272184, 34.402961 ], [ -114.280108, 34.403147 ], [ -114.282261, 34.403641 ], [ -114.286802, 34.40534 ], [ -114.288663, 34.406623 ], [ -114.290219, 34.408291 ], [ -114.291751, 34.411104 ], [ -114.291903, 34.416231 ], [ -114.292226, 34.417606 ], [ -114.294836, 34.421389 ], [ -114.301016000000104, 34.426807 ], [ -114.308659, 34.430485 ], [ -114.312251, 34.432726 ], [ -114.319054, 34.435831 ], [ -114.32613, 34.437251 ], [ -114.32688, 34.438048 ], [ -114.330669, 34.445295 ], [ -114.332991, 34.448082 ], [ -114.335372, 34.450038 ], [ -114.339627, 34.451435 ], [ -114.342615, 34.451442 ], [ -114.348974, 34.450166 ], [ -114.356025, 34.449744 ], [ -114.363404000000102, 34.447773 ], [ -114.373719, 34.446938 ], [ -114.375789, 34.447798 ], [ -114.378852, 34.450376 ], [ -114.382985, 34.453971 ], [ -114.386699, 34.457911 ], [ -114.387407, 34.460492 ], [ -114.387187, 34.462021 ], [ -114.383525, 34.470405 ], [ -114.381701, 34.47604 ], [ -114.381555, 34.477883 ], [ -114.383038, 34.488903 ], [ -114.382358, 34.495758 ], [ -114.381402, 34.499245 ], [ -114.378124, 34.507288 ], [ -114.378223, 34.516521 ], [ -114.380838, 34.529724 ], [ -114.389603, 34.542982 ], [ -114.398847, 34.559149 ], [ -114.405228, 34.569637 ], [ -114.422382, 34.580711 ], [ -114.435671, 34.593841 ], [ -114.43681, 34.596074 ], [ -114.436363, 34.596797 ], [ -114.427502, 34.599227 ], [ -114.425338, 34.600842 ], [ -114.424326, 34.602338 ], [ -114.424202, 34.610453 ], [ -114.428648, 34.614641 ], [ -114.438739, 34.621455 ], [ -114.439495, 34.625858 ], [ -114.441398, 34.630171 ], [ -114.441525, 34.631529 ], [ -114.440685, 34.634739 ], [ -114.440294, 34.63824 ], [ -114.440519, 34.640066 ], [ -114.441465, 34.64253 ], [ -114.444276, 34.646542 ], [ -114.445664, 34.647542 ], [ -114.449549, 34.651423 ], [ -114.457985, 34.657113 ], [ -114.45821, 34.657994 ], [ -114.457702, 34.659328 ], [ -114.457185, 34.659992 ], [ -114.451785, 34.663891 ], [ -114.450614, 34.665793 ], [ -114.450506, 34.666836 ], [ -114.451532, 34.668605 ], [ -114.454305, 34.671234 ], [ -114.45491, 34.673092 ], [ -114.454881, 34.675639 ], [ -114.455536, 34.677335 ], [ -114.458163, 34.681161 ], [ -114.462178, 34.6858 ], [ -114.463633, 34.68794 ], [ -114.465246, 34.691202 ], [ -114.46809, 34.701786 ], [ -114.46813, 34.704445 ], [ -114.46862, 34.707573 ], [ -114.470477, 34.711368 ], [ -114.47162, 34.712966 ], [ -114.473682, 34.713964 ], [ -114.477297, 34.714514 ], [ -114.482779, 34.714511 ], [ -114.487508, 34.716626 ], [ -114.489287, 34.720155 ], [ -114.490971, 34.724848 ], [ -114.492017, 34.725702 ], [ -114.495858, 34.727956 ], [ -114.499007, 34.729096 ], [ -114.500795, 34.730418 ], [ -114.510292, 34.733582 ], [ -114.514178, 34.735288 ], [ -114.516619, 34.736745 ], [ -114.521048, 34.741173 ], [ -114.522619, 34.74373 ], [ -114.525611, 34.747005 ], [ -114.529079, 34.750006 ], [ -114.529615, 34.750822 ], [ -114.540306, 34.757109 ], [ -114.546884, 34.761802 ], [ -114.552682, 34.766871 ], [ -114.558653, 34.773852 ], [ -114.563979, 34.782597 ], [ -114.565184, 34.785976 ], [ -114.569383, 34.791568 ], [ -114.571010000000101, 34.794294 ], [ -114.574474, 34.804214 ], [ -114.574694, 34.807471 ], [ -114.576452, 34.8153 ], [ -114.578681000000103, 34.820977 ], [ -114.581126, 34.826115 ], [ -114.586842, 34.835672 ], [ -114.592339, 34.841153 ], [ -114.600653, 34.847361 ], [ -114.604255, 34.849573 ], [ -114.619878, 34.856873 ], [ -114.623939, 34.859738 ], [ -114.628276, 34.863596 ], [ -114.630682000000107, 34.866352 ], [ -114.633051, 34.869971 ], [ -114.634382, 34.87289 ], [ -114.635176, 34.875003 ], [ -114.635458, 34.876902 ] ] ] ] }
`


================================================
FILE: cmd/tile38-benchmark/main.go
================================================
package main

import (
	"fmt"
	"log"
	"math"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/tidwall/redbench"
	"github.com/tidwall/redcon"
	"github.com/tidwall/tile38/cmd/tile38-benchmark/az"
	"github.com/tidwall/tile38/core"
)

var (
	hostname = "127.0.0.1"
	port     = 9851
	auth     = ""
	clients  = 50
	requests = 100000
	quiet    = false
	pipeline = 1
	csv      = false
	json     = false
	allTests = "PING,SET,GET,INTERSECTS,WITHIN,NEARBY,EVAL"
	tests    = allTests
	redis    = false
)

var addr string

func showHelp() bool {
	gitsha := ""
	if core.GitSHA == "" || core.GitSHA == "0000000" {
		gitsha = ""
	} else {
		gitsha = " (git:" + core.GitSHA + ")"
	}
	fmt.Fprintf(os.Stdout, "tile38-benchmark %s%s\n\n", core.Version, gitsha)
	fmt.Fprintf(os.Stdout, "Usage: tile38-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests>]\n")

	fmt.Fprintf(os.Stdout, " -h <hostname>      Server hostname (default: %s)\n", hostname)
	fmt.Fprintf(os.Stdout, " -p <port>          Server port (default: %d)\n", port)
	fmt.Fprintf(os.Stdout, " -a <password>      Password for Tile38 Auth\n")
	fmt.Fprintf(os.Stdout, " -c <clients>       Number of parallel connections (default %d)\n", clients)
	fmt.Fprintf(os.Stdout, " -n <requests>      Total number or requests (default %d)\n", requests)
	fmt.Fprintf(os.Stdout, " -q                 Quiet. Just show query/sec values\n")
	fmt.Fprintf(os.Stdout, " -P <numreq>        Pipeline <numreq> requests. Default 1 (no pipeline).\n")
	fmt.Fprintf(os.Stdout, " -t <tests>         Only run the comma separated list of tests. The test\n")
	fmt.Fprintf(os.Stdout, "                    names are the same as the ones produced as output.\n")
	fmt.Fprintf(os.Stdout, " --csv              Output in CSV format.\n")
	fmt.Fprintf(os.Stdout, " --json             Request JSON responses (default is RESP output)\n")
	fmt.Fprintf(os.Stdout, " --redis            Runs against a Redis server\n")
	fmt.Fprintf(os.Stdout, "\n")
	return false
}

func parseArgs() bool {
	defer func() {
		if v := recover(); v != nil {
			if v, ok := v.(string); ok && v == "bad arg" {
				showHelp()
			}
		}
	}()

	args := os.Args[1:]
	readArg := func(arg string) string {
		if len(args) == 0 {
			panic("bad arg")
		}
		var narg = args[0]
		args = args[1:]
		return narg
	}
	readIntArg := func(arg string) int {
		n, err := strconv.ParseUint(readArg(arg), 10, 64)
		if err != nil {
			panic("bad arg")
		}
		return int(n)
	}
	badArg := func(arg string) bool {
		fmt.Fprintf(os.Stderr, "Unrecognized option or bad number of args for: '%s'\n", arg)
		return false
	}

	for len(args) > 0 {
		arg := readArg("")
		if arg == "--help" || arg == "-?" {
			return showHelp()
		}
		if !strings.HasPrefix(arg, "-") {
			args = append([]string{arg}, args...)
			break
		}
		switch arg {
		default:
			return badArg(arg)
		case "-h":
			hostname = readArg(arg)
		case "-p":
			port = readIntArg(arg)
		case "-a":
			auth = readArg(arg)
		case "-c":
			clients = readIntArg(arg)
			if clients <= 0 {
				clients = 1
			}
		case "-n":
			requests = readIntArg(arg)
			if requests <= 0 {
				requests = 0
			}
		case "-q":
			quiet = true
		case "-P":
			pipeline = readIntArg(arg)
			if pipeline <= 0 {
				pipeline = 1
			}
		case "-t":
			tests = readArg(arg)
		case "--csv":
			csv = true
		case "--json":
			json = true
		case "--redis":
			redis = true
		}
	}
	return true
}

func fillOpts() *redbench.Options {
	opts := *redbench.DefaultOptions
	opts.CSV = csv
	opts.Clients = clients
	opts.Pipeline = pipeline
	opts.Quiet = quiet
	opts.Requests = requests
	opts.Stderr = os.Stderr
	opts.Stdout = os.Stdout
	return &opts
}

func randPoint() (lat, lon float64) {
	return rand.Float64()*180 - 90, rand.Float64()*360 - 180
}

func isValidRect(minlat, minlon, maxlat, maxlon float64) bool {
	return minlat > -90 && maxlat < 90 && minlon > -180 && maxlon < 180
}

func randRect(meters float64) (minlat, minlon, maxlat, maxlon float64) {
	for {
		lat, lon := randPoint()
		maxlat, _ = destinationPoint(lat, lon, meters, 0)
		_, maxlon = destinationPoint(lat, lon, meters, 90)
		minlat, _ = destinationPoint(lat, lon, meters, 180)
		_, minlon = destinationPoint(lat, lon, meters, 270)
		if isValidRect(minlat, minlon, maxlat, maxlon) {
			return
		}
	}
}

func prepFn(conn net.Conn) bool {
	var resp [64]byte
	conn.Write([]byte("CONFIG GET requirepass\r\n"))
	n, err := conn.Read(resp[:])
	if err != nil {
		log.Fatal(err)
	}
	if string(resp[:n]) == "-ERR authentication required\r\n" {
		if auth == "" {
			log.Fatal("invalid auth")
		} else {
			cmd := redcon.AppendArray(nil, 2)
			cmd = redcon.AppendBulkString(cmd, "AUTH")
			cmd = redcon.AppendBulkString(cmd, auth)
			conn.Write(cmd)
			n, err := conn.Read(resp[:])
			if err != nil || string(resp[:n]) != "+OK\r\n" {
				log.Fatal("invalid auth")
			}
		}
	} else if auth != "" {
		log.Fatal("invalid auth")
	}
	if json {
		conn.Write([]byte("output json\r\n"))
		conn.Read(make([]byte, 64))
	}
	return true
}
func main() {
	rand.Seed(time.Now().UnixNano())
	if !parseArgs() {
		return
	}
	opts := fillOpts()
	addr = fmt.Sprintf("%s:%d", hostname, port)

	testsArr := strings.Split(allTests, ",")
	var subtract bool
	var add bool
	for _, test := range strings.Split(tests, ",") {
		if strings.HasPrefix(test, "-") {
			if add {
				os.Stderr.Write([]byte("test flag cannot mix add and subtract\n"))
				os.Exit(1)
			}
			subtract = true
			for i := range testsArr {
				if strings.EqualFold(testsArr[i], test[1:]) {
					testsArr = append(testsArr[:i], testsArr[i+1:]...)
					break
				}
			}
		} else if subtract {
			add = true
			os.Stderr.Write([]byte("test flag cannot mix add and subtract\n"))
			os.Exit(1)
		}
	}
	if !subtract {
		testsArr = strings.Split(tests, ",")
	}

	for _, test := range testsArr {
		switch strings.ToUpper(strings.TrimSpace(test)) {
		case "PING":
			redbench.Bench("PING", addr, opts, prepFn,
				func(buf []byte) []byte {
					return redbench.AppendCommand(buf, "PING")
				},
			)
		case "GEOADD":
			//GEOADD key longitude latitude member
			if redis {
				var i int64
				redbench.Bench("GEOADD", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						lat, lon := randPoint()
						return redbench.AppendCommand(buf, "GEOADD", "key:bench",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"id:"+strconv.FormatInt(i, 10),
						)
					},
				)
			}

		case "SET", "SET-POINT", "SET-RECT", "SET-LINE", "SET-STRING":
			if redis {
				redbench.Bench("SET", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf, "SET", "key:__rand_int__", "xxx")
					},
				)
			} else {
				var i int64
				switch strings.ToUpper(strings.TrimSpace(test)) {
				case "SET", "SET-POINT":
					redbench.Bench("SET (point)", addr, opts, prepFn,
						func(buf []byte) []byte {
							i := atomic.AddInt64(&i, 1)
							lat, lon := randPoint()
							return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "POINT",
								strconv.FormatFloat(lat, 'f', 5, 64),
								strconv.FormatFloat(lon, 'f', 5, 64),
							)
						},
					)
				}
				switch strings.ToUpper(strings.TrimSpace(test)) {
				case "SET", "SET-RECT":
					redbench.Bench("SET (rect)", addr, opts, prepFn,
						func(buf []byte) []byte {
							i := atomic.AddInt64(&i, 1)
							minlat, minlon, maxlat, maxlon := randRect(10000)
							return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "BOUNDS",
								strconv.FormatFloat(minlat, 'f', 5, 64),
								strconv.FormatFloat(minlon, 'f', 5, 64),
								strconv.FormatFloat(maxlat, 'f', 5, 64),
								strconv.FormatFloat(maxlon, 'f', 5, 64),
							)
						},
					)
				}
				switch strings.ToUpper(strings.TrimSpace(test)) {
				case "SET", "SET-LINE":
					redbench.Bench("SET (line)", addr, opts, prepFn,
						func(buf []byte) []byte {
							i := atomic.AddInt64(&i, 1)
							alat, alon, blat, blon := randRect(10000)
							if rand.Int()%2 == 0 {
								alat, alon, blat, blon = blat, blon, alat, alon
							}
							linestring := fmt.Sprintf(`{"type":"LineString","coordinates":[[%f,%f],[%f,%f]]}`, alon, alat, blon, blat)
							return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "OBJECT",
								linestring,
							)
						},
					)
				}
				switch strings.ToUpper(strings.TrimSpace(test)) {
				case "SET", "SET-STRING":
					redbench.Bench("SET (string)", addr, opts, prepFn,
						func(buf []byte) []byte {
							i := atomic.AddInt64(&i, 1)
							return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "STRING", "xxx")
						},
					)
				}
			}
		case "GET":
			if redis {
				redbench.Bench("GET", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf, "GET", "key:__rand_int__")
					},
				)
			} else {
				var i int64
				redbench.Bench("GET (point)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "GET", "key:bench", "id:"+strconv.FormatInt(i, 10), "POINT")
					},
				)
				redbench.Bench("GET (rect)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "GET", "key:bench", "id:"+strconv.FormatInt(i, 10), "BOUNDS")
					},
				)
				redbench.Bench("GET (string)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "GET", "key:bench", "id:"+strconv.FormatInt(i, 10), "OBJECT")
					},
				)
			}
		case "INTERSECTS",
			"INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-1000", "INTERSECTS-BOUNDS-10000", "INTERSECTS-BOUNDS-100000",
			"INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000", "INTERSECTS-CIRCLE-10000", "INTERSECTS-CIRCLE-100000",
			"INTERSECTS-AZ":
			if redis {
				break
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000":
				redbench.Bench("INTERSECTS (intersects-circle 1km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"1000")
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-10000":
				redbench.Bench("INTERSECTS (intersects-circle 10km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"10000")
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-100000":
				redbench.Bench("INTERSECTS (intersects-circle 100km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"100000")
					},
				)
			}
			// INTERSECTS-BOUNDS
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-1000":
				minlat, minlon, maxlat, maxlon := randRect(1000)
				redbench.Bench("INTERSECTS (intersects-bounds 1km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-10000":
				minlat, minlon, maxlat, maxlon := randRect(10000)
				redbench.Bench("INTERSECTS (intersects-bounds 10km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-100000":
				minlat, minlon, maxlat, maxlon := randRect(10000)
				redbench.Bench("INTERSECTS (intersects-bounds 100km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}

			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "INTERSECTS", "INTERSECTS-AZ":
				var mu sync.Mutex
				var loaded bool
				redbench.Bench("INTERSECTS (intersects-az limit 5)", addr, opts, func(conn net.Conn) bool {
					func() {
						mu.Lock()
						defer mu.Unlock()
						if loaded {
							return
						}
						loaded = true
						p := make([]byte, 0xFF)
						conn.Write([]byte("GET keys:bench:geo az point\r\n"))
						n, err := conn.Read(p)
						if err != nil {
							panic(err)
						}
						if string(p[:n]) != "$-1\r\n" {
							return
						}
						args := []string{"SET", "key:bench:geo", "az", "object", az.JSON}
						out := redcon.AppendArray(nil, len(args))
						for _, arg := range args {
							out = redcon.AppendBulkString(out, arg)
						}
						conn.Write(out)
						n, err = conn.Read(p)
						if err != nil {
							panic(err)
						}
						if string(p[:n]) != "+OK\r\n" {
							panic("expected OK")
						}
					}()
					return prepFn(conn)
				},
					func(buf []byte) []byte {
						args := []string{"INTERSECTS", "key:bench", "LIMIT", "5",
							"COUNT", "GET", "key:bench:geo", "az"}
						return redbench.AppendCommand(buf, args...)
					},
				)
			}

		case "WITHIN",
			"WITHIN-RECT", "WITHIN-RECT-1000", "WITHIN-RECT-10000", "WITHIN-RECT-100000",
			"WITHIN-CIRCLE", "WITHIN-CIRCLE-1000", "WITHIN-CIRCLE-10000", "WITHIN-CIRCLE-100000":
			if redis {
				break
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-1000":
				redbench.Bench("WITHIN (within-circle 1km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"1000")
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-10000":
				redbench.Bench("WITHIN (within-circle 10km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"10000")
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-100000":
				redbench.Bench("WITHIN (within-circle 100km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "CIRCLE",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"100000")
					},
				)
			}
			// WITHIN-BOUNDS
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-1000":
				minlat, minlon, maxlat, maxlon := randRect(1000)
				redbench.Bench("WITHIN (within-bounds 1km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-10000":
				minlat, minlon, maxlat, maxlon := randRect(10000)
				redbench.Bench("WITHIN (within-bounds 10km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-100000":
				minlat, minlon, maxlat, maxlon := randRect(10000)
				redbench.Bench("WITHIN (within-bounds 100km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						return redbench.AppendCommand(buf,
							"WITHIN", "key:bench", "COUNT", "BOUNDS",
							strconv.FormatFloat(minlat, 'f', 5, 64),
							strconv.FormatFloat(minlon, 'f', 5, 64),
							strconv.FormatFloat(maxlat, 'f', 5, 64),
							strconv.FormatFloat(maxlon, 'f', 5, 64))
					},
				)
			}
		case "NEARBY",
			"NEARBY-KNN", "NEARBY-KNN-1", "NEARBY-KNN-10", "NEARBY-KNN-100",
			"NEARBY-POINT", "NEARBY-POINT-1000", "NEARBY-POINT-10000", "NEARBY-POINT-100000":
			if redis {
				break
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-1":
				redbench.Bench("NEARBY (limit 1)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "LIMIT", "1", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
						)
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-10":
				redbench.Bench("NEARBY (limit 10)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "LIMIT", "10", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
						)
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-100":
				redbench.Bench("NEARBY (limit 100)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "LIMIT", "100", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
						)
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-1000":
				redbench.Bench("NEARBY (point 1km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"1000",
						)
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-10000":
				redbench.Bench("NEARBY (point 10km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"10000",
						)
					},
				)
			}
			switch strings.ToUpper(strings.TrimSpace(test)) {
			case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-100000":
				redbench.Bench("NEARBY (point 100km)", addr, opts, prepFn,
					func(buf []byte) []byte {
						lat, lon := randPoint()
						return redbench.AppendCommand(buf,
							"NEARBY", "key:bench", "COUNT", "POINT",
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
							"100000",
						)
					},
				)
			}
		case "EVAL":
			if !redis {
				var i int64
				getScript := "return tile38.call('GET', KEYS[1], ARGV[1], 'point')"
				get4Script :=
					"local a = tile38.call('GET', KEYS[1], ARGV[1], 'point');" +
						"local b = tile38.call('GET', KEYS[1], ARGV[2], 'point');" +
						"local c = tile38.call('GET', KEYS[1], ARGV[3], 'point');" +
						"local d = tile38.call('GET', KEYS[1], ARGV[4], 'point');" +
						"return d"

				setScript := "return tile38.call('SET', KEYS[1], ARGV[1], 'point', ARGV[2], ARGV[3])"
				if !opts.Quiet {
					fmt.Println("Scripts to run:")
					fmt.Println("GET SCRIPT: " + getScript)
					fmt.Println("GET FOUR SCRIPT: " + get4Script)
					fmt.Println("SET SCRIPT: " + setScript)
				}

				redbench.Bench("EVAL (set point)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						lat, lon := randPoint()
						return redbench.AppendCommand(buf, "EVAL", setScript, "1",
							"key:bench",
							"id:"+strconv.FormatInt(i, 10),
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
						)
					},
				)
				redbench.Bench("EVALNA (set point)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						lat, lon := randPoint()
						return redbench.AppendCommand(buf, "EVALNA", setScript, "1",
							"key:bench",
							"id:"+strconv.FormatInt(i, 10),
							strconv.FormatFloat(lat, 'f', 5, 64),
							strconv.FormatFloat(lon, 'f', 5, 64),
						)
					},
				)
				redbench.Bench("EVALRO (get point)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "EVALRO", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10))
					},
				)
				redbench.Bench("EVALRO (get 4 points)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "EVALRO", get4Script, "1",
							"key:bench",
							"id:"+strconv.FormatInt(i, 10),
							"id:"+strconv.FormatInt(i+1, 10),
							"id:"+strconv.FormatInt(i+2, 10),
							"id:"+strconv.FormatInt(i+3, 10),
						)
					},
				)
				redbench.Bench("EVALNA (get point)", addr, opts, prepFn,
					func(buf []byte) []byte {
						i := atomic.AddInt64(&i, 1)
						return redbench.AppendCommand(buf, "EVALNA", getScript, "1", "key:bench", "id:"+strconv.FormatInt(i, 10))
					},
				)
			}
		}
	}
}

const earthRadius = 6371e3

func toRadians(deg float64) float64 { return deg * math.Pi / 180 }
func toDegrees(rad float64) float64 { return rad * 180 / math.Pi }

// destinationPoint return the destination from a point based on a distance and bearing.
func destinationPoint(lat, lon, meters, bearingDegrees float64) (destLat, destLon float64) {
	// see http://williams.best.vwh.net/avform.htm#LL
	δ := meters / earthRadius // angular distance in radians
	θ := toRadians(bearingDegrees)
	φ1 := toRadians(lat)
	λ1 := toRadians(lon)
	φ2 := math.Asin(math.Sin(φ1)*math.Cos(δ) + math.Cos(φ1)*math.Sin(δ)*math.Cos(θ))
	λ2 := λ1 + math.Atan2(math.Sin(θ)*math.Sin(δ)*math.Cos(φ1), math.Cos(δ)-math.Sin(φ1)*math.Sin(φ2))
	λ2 = math.Mod(λ2+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180°
	return toDegrees(φ2), toDegrees(λ2)
}


================================================
FILE: cmd/tile38-cli/main.go
================================================
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strconv"
	"strings"

	"github.com/peterh/liner"
	"github.com/tidwall/gjson"
	"github.com/tidwall/resp"
	"github.com/tidwall/tile38/core"
)

func getEnv(name string, defaultValue string) string {
	val, exists := os.LookupEnv(name)
	if !exists {
		return defaultValue
	}
	return val
}

func userHomeDir() string {
	if runtime.GOOS == "windows" {
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return home
	}
	return os.Getenv("HOME")
}

var (
	historyFile = filepath.Join(userHomeDir(), ".liner_example_history")
)

type connError struct {
	OK  bool   `json:"ok"`
	Err string `json:"err"`
}

var (
	hostname   = "127.0.0.1"
	output     = "json"
	port       = 9851
	oneCommand string
	raw        bool
	noprompt   bool
	tty        bool
	stdin      bool
)

func showHelp() bool {

	gitsha := ""
	if core.GitSHA == "" || core.GitSHA == "0000000" {
		gitsha = ""
	} else {
		gitsha = " (git:" + core.GitSHA + ")"
	}
	fmt.Fprintf(os.Stdout, "tile38-cli %s%s\n\n", core.Version, gitsha)
	fmt.Fprintf(os.Stdout, "Usage: tile38-cli [OPTIONS] [cmd [arg [arg ...]]]\n")
	fmt.Fprintf(os.Stdout, " --raw              Use raw formatting for replies\n")
	fmt.Fprintf(os.Stdout, " --noprompt         Do not display a prompt\n")
	fmt.Fprintf(os.Stdout, " --resp             Use RESP output formatting (default is JSON output)\n")
	fmt.Fprintf(os.Stdout, " --json             Use JSON output formatting (default is JSON output)\n")
	fmt.Fprintf(os.Stdout, " -h <hostname>      Server hostname (default: %s)\n", hostname)
	fmt.Fprintf(os.Stdout, " -p <port>          Server port (default: %d)\n", port)
	fmt.Fprintf(os.Stdout, " -x                 Read last argument from STDIN.\n")
	fmt.Fprintf(os.Stdout, "\n")
	return false
}

func parseArgs() bool {
	defer func() {
		if v := recover(); v != nil {
			if v, ok := v.(string); ok && v == "bad arg" {
				showHelp()
			}
		}
	}()

	hostname = getEnv("TILE38_HOSTNAME", hostname)
	output = getEnv("TILE38_OUTPUT", output)
	portStr := getEnv("TILE38_PORT", "")

	if portStr != "" {
		tempPort, err := strconv.Atoi(portStr)
		if err == nil {
			port = tempPort
		}
	}

	args := os.Args[1:]
	readArg := func(arg string) string {
		if len(args) == 0 {
			panic("bad arg")
		}
		var narg = args[0]
		args = args[1:]
		return narg
	}
	badArg := func(arg string) bool {
		fmt.Fprintf(os.Stderr, "Unrecognized option or bad number of args for: '%s'\n", arg)
		return false
	}

	for len(args) > 0 {
		arg := readArg("")
		if arg == "--help" || arg == "-?" {
			return showHelp()
		}
		if !strings.HasPrefix(arg, "-") {
			args = append([]string{arg}, args...)
			break
		}
		switch arg {
		default:
			return badArg(arg)
		case "--raw":
			raw = true
		case "--tty":
			tty = true
		case "--noprompt":
			noprompt = true
		case "--resp":
			output = "resp"
		case "--json":
			output = "json"
		case "-x":
			stdin = true
		case "-h":
			hostname = readArg(arg)
		case "-p":
			n, err := strconv.ParseUint(readArg(arg), 10, 16)
			if err != nil {
				return badArg(arg)
			}
			port = int(n)
		}
	}
	oneCommand = strings.Join(args, " ")
	if stdin {
		data, err := io.ReadAll(os.Stdin)
		if err != nil {
			println(err)
		}
		if !gjson.ValidBytes(data) {
			fmt.Fprintf(os.Stderr, "Invalid STDIN: Not JSON\n")
			return false
		}
		arg := strings.Replace(string(data), "\r", "", -1)
		arg = strings.Replace(arg, "\n", "", -1)
		arg = strings.Replace(arg, "'", "\\'", -1)
		oneCommand += " '" + arg + "'"
	}
	return true
}

func refusedErrorString(addr string) string {
	return fmt.Sprintf("Could not connect to Tile38 at %s: Connection refused", addr)
}

var groupsM = make(map[string][]string)

func jsonOK(msg []byte) bool {
	return gjson.GetBytes(msg, "ok").Bool()
}

func main() {
	if !parseArgs() {
		return
	}

	if len(oneCommand) > 0 && strings.Split(strings.ToLower(oneCommand), " ")[0] == "help" {
		showHelp()
		return
	}

	addr := fmt.Sprintf("%s:%d", hostname, port)
	var conn *client
	connDial := func() {
		var err error
		conn, err = clientDial("tcp", addr)
		if err != nil {
			if _, ok := err.(net.Error); ok {
				fmt.Fprintln(os.Stderr, refusedErrorString(addr))
			} else {
				fmt.Fprintln(os.Stderr, err.Error())
				os.Exit(1)
			}
			if oneCommand != "" {
				os.Exit(1)
			}
		} else if _, err := conn.Do("output " + output); err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
			os.Exit(1)
		}
	}
	connDial()
	monitor := false
	livemode := false
	aof := false
	defer func() {
		if livemode {
			var err error
			if aof {
				_, err = io.Copy(os.Stdout, conn.Reader())
				fmt.Fprintln(os.Stderr, "")
			} else {
				var msg []byte
				for {
					msg, err = conn.readLiveResp()
					if err != nil {
						break
					}
					if !raw {
						if output == "resp" {
							msg = convert2termresp(msg)
						} else {
							msg = convert2termjson(msg)
						}
					}
					fmt.Fprintln(os.Stderr, string(msg))
				}
			}
			if err != nil && err != io.EOF {
				fmt.Fprintln(os.Stderr, err.Error())
			}
		}
	}()

	line := liner.NewLiner()
	defer line.Close()

	var commands []string
	for name, command := range core.Commands {
		commands = append(commands, name)
		groupsM[command.Group] = append(groupsM[command.Group], name)
	}
	sort.Strings(commands)
	var groups []string
	for group, arr := range groupsM {
		groups = append(groups, "@"+group)
		sort.Strings(arr)
		groupsM[group] = arr
	}
	sort.Strings(groups)

	line.SetMultiLineMode(false)
	line.SetCtrlCAborts(true)
	if !(noprompt && tty) {
		line.SetCompleter(func(line string) (c []string) {
			if strings.HasPrefix(strings.ToLower(line), "help ") {
				var nitems []string
				nline := strings.TrimSpace(line[5:])
				if nline == "" || nline[0] == '@' {
					for _, n := range groups {
						if strings.HasPrefix(strings.ToLower(n), strings.ToLower(nline)) {
							nitems = append(nitems, line[:len(line)-len(nline)]+strings.ToLower(n))
						}
					}
				} else {
					for _, n := range commands {
						if strings.HasPrefix(strings.ToLower(n), strings.ToLower(nline)) {
							nitems = append(nitems, line[:len(line)-len(nline)]+strings.ToUpper(n))
						}
					}
				}
				for _, n := range nitems {
					if strings.HasPrefix(strings.ToLower(n), strings.ToLower(line)) {
						c = append(c, n)
					}
				}
			} else {
				for _, n := range commands {
					if strings.HasPrefix(strings.ToLower(n), strings.ToLower(line)) {
						c = append(c, n)
					}
				}
			}
			return
		})
	}
	if f, err := os.Open(historyFile); err == nil {
		line.ReadHistory(f)
		f.Close()
	}
	defer func() {
		if f, err := os.Create(historyFile); err != nil {
			fmt.Fprintln(os.Stderr, err.Error())
		} else {
			line.WriteHistory(f)
			f.Close()
		}
	}()

	password := getEnv("TILE38_PASSWORD", "")

	if conn != nil && password != "" {
		conn.Do(fmt.Sprintf("auth %s", password))
	}

	for {

		var command string
		var err error
		if oneCommand == "" {
			if raw || noprompt {
				command, err = line.Prompt("")
			} else {
				if conn == nil {
					command, err = line.Prompt("not connected> ")
				} else {
					command, err = line.Prompt(addr + "> ")
				}
			}

		} else {
			command = oneCommand
		}
		if err == nil {
			nohist := strings.HasPrefix(command, " ")
			command = strings.TrimSpace(command)
			if command == "" {
				if conn != nil {
					_, err := conn.Do("pInG")
					if err != nil {
						if err != io.EOF && !strings.Contains(err.Error(), "broken pipe") {
							fmt.Fprintln(os.Stderr, err.Error())
						} else {
							fmt.Fprintln(os.Stderr, refusedErrorString(addr))
						}
						conn.wr.Close()
						conn = nil
						continue
					}
				}
			} else {
				if !nohist {
					line.AppendHistory(command)
				}
				if strings.ToLower(command) == "exit" {
					return
				}
				if strings.ToLower(command) == "quit" {
					return
				}
				if strings.ToLower(command) == "clear" {
					clearScreen()
					continue
				}
				if strings.ToLower(command) == "help" || strings.HasPrefix(strings.ToLower(command), "help") {
					err = help(strings.TrimSpace(command[4:]))
					if err != nil {
						return
					}
					continue
				}
				aof = strings.HasPrefix(strings.ToLower(command), "aof ")
			tryAgain:
				if conn == nil {
					connDial()
					if conn == nil {
						continue
					}
				}
				msg, err := conn.Do(command)
				if err != nil {
					if err != io.EOF {
						fmt.Fprintln(os.Stderr, err.Error())
					}
					conn.wr.Close()
					conn = nil
					goto tryAgain
				}
				switch strings.ToLower(command) {
				case "output resp":
					if string(msg) == "+OK\r\n" {
						output = "resp"
					}
				case "output json":
					if jsonOK(msg) {
						output = "json"
					}
				case "monitor":
					monitor = true
					livemode = true
					output = "resp"
				}
				if output == "resp" &&
					(strings.HasPrefix(string(msg), "*3\r\n$10\r\npsubscribe\r\n") ||
						strings.HasPrefix(string(msg), "*3\r\n$9\r\nsubscribe\r\n")) {
					livemode = true
				}
				if !raw {
					if output == "resp" {
						msg = convert2termresp(msg)
					} else {
						msg = convert2termjson(msg)
					}
				}

				if !livemode && output == "json" {
					if gjson.GetBytes(msg, "command").String() == "psubscribe" ||
						gjson.GetBytes(msg, "command").String() == "subscribe" ||
						string(msg) == liveJSON {
						livemode = true
					}
				}

				mustOutput := true
				if !monitor && oneCommand == "" && output == "json" && !jsonOK(msg) {
					var cerr connError
					if err := json.Unmarshal(msg, &cerr); err == nil {
						fmt.Fprintln(os.Stderr, "(error) "+cerr.Err)
						mustOutput = false
					}
				} else if livemode {
					fmt.Fprintln(os.Stderr, string(msg))
					break // break out of prompt and just feed data to screen
				}
				if mustOutput {
					fmt.Fprintln(os.Stdout, string(msg))
				}
			}
		} else if err == liner.ErrPromptAborted {
			return
		} else if err == io.EOF {
			os.Exit(0)
		} else {
			fmt.Fprintf(os.Stderr, "Error reading line: %s", err.Error())
		}
		if oneCommand != "" {
			return
		}
	}
}

func convert2termresp(msg []byte) []byte {
	rd := resp.NewReader(bytes.NewBuffer(msg))
	out := ""
	for {
		v, _, err := rd.ReadValue()
		if err != nil {
			break
		}
		out += convert2termrespval(v, 0)
	}
	return []byte(strings.TrimSpace(out))
}

func convert2termjson(msg []byte) []byte {
	if msg[0] == '{' {
		return msg
	}
	return bytes.TrimSpace(msg[bytes.IndexByte(msg, '\n')+1:])
}

func convert2termrespval(v resp.Value, spaces int) string {
	switch v.Type() {
	default:
		return v.String()
	case resp.BulkString:
		if v.IsNull() {
			return "(nil)"
		}
		return "\"" + v.String() + "\""
	case resp.Integer:
		return "(integer) " + v.String()
	case resp.Error:
		return "(error) " + v.String()
	case resp.Array:
		arr := v.Array()
		if len(arr) == 0 {
			return "(empty list or set)"
		}
		out := ""
		nspaces := spaces + numlen(len(arr))
		for i, v := range arr {
			if i > 0 {
				out += strings.Repeat(" ", spaces)
			}
			iout := strings.TrimSpace(convert2termrespval(v, nspaces+2))
			out += fmt.Sprintf("%d) %s\n", i+1, iout)
		}
		return out
	}
}

func numlen(n int) int {
	l := 1
	if n < 0 {
		l++
		n = n * -1
	}
	for i := 0; i < 1000; i++ {
		if n < 10 {
			break
		}
		l++
		n = n / 10
	}
	return l
}

func help(arg string) error {
	var groupsA []string
	for group := range groupsM {
		groupsA = append(groupsA, "@"+group)
	}
	groups := "Groups: " + strings.Join(groupsA, ", ") + "\n"

	if arg == "" {
		fmt.Fprintf(os.Stderr, "tile38-cli %s (git:%s)\n", core.Version, core.GitSHA)
		fmt.Fprintf(os.Stderr, `Type:   "help @<group>" to get a list of commands in <group>`+"\n")
		fmt.Fprintf(os.Stderr, `        "help <command>" for help on <command>`+"\n")
		if !(noprompt && tty) {
			fmt.Fprintf(os.Stderr, `        "help <tab>" to get a list of possible help topics`+"\n")
		}
		fmt.Fprintf(os.Stderr, `        "quit" to exit`+"\n")
		if noprompt && tty {
			fmt.Fprint(os.Stderr, groups)
		}
		return nil
	}
	showGroups := false
	found := false
	if strings.HasPrefix(arg, "@") {
		for _, command := range groupsM[arg[1:]] {
			fmt.Fprintf(os.Stderr, "%s\n", core.Commands[command].TermOutput("  "))
			found = true
		}
		if !found {
			showGroups = true
		}
	} else {
		if command, ok := core.Commands[strings.ToUpper(arg)]; ok {
			fmt.Fprintf(os.Stderr, "%s\n", command.TermOutput("  "))
			found = true
		}
	}
	if showGroups {
		if noprompt && tty {
			fmt.Fprint(os.Stderr, groups)
		}
	} else if !found {
		if noprompt && tty {
			help("")
		}
	}
	return nil
}

const liveJSON = `{"ok":true,"live":true}`

type client struct {
	wr net.Conn
	rd *bufio.Reader
}

func clientDial(network, addr string) (*client, error) {
	conn, err := net.Dial(network, addr)
	if err != nil {
		return nil, err
	}
	return &client{wr: conn, rd: bufio.NewReader(conn)}, nil
}

func (c *client) Do(command string) ([]byte, error) {
	_, err := c.wr.Write(plainToCompat(command))
	if err != nil {
		return nil, err
	}
	return c.readResp()
}

func (c *client) readResp() ([]byte, error) {
	ch, err := c.rd.Peek(1)
	if err != nil {
		return nil, err
	}
	switch ch[0] {
	case ':', '+', '-', '{':
		return c.readLine()
	case '$':
		return c.readBulk()
	case '*':
		return c.readArray()
	default:
		return nil, fmt.Errorf("invalid response character '%c", ch[0])
	}
}

func (c *client) readArray() ([]byte, error) {
	out, err := c.readLine()
	if err != nil {
		return nil, err
	}
	n, err := strconv.ParseUint(string(bytes.TrimSpace(out[1:])), 10, 64)
	if err != nil {
		return nil, err
	}
	for i := 0; i < int(n); i++ {
		resp, err := c.readResp()
		if err != nil {
			return nil, err
		}
		out = append(out, resp...)
	}
	return out, nil
}

func (c *client) readBulk() ([]byte, error) {
	line, err := c.readLine()
	if err != nil {
		return nil, err
	}
	x, err := strconv.ParseInt(string(bytes.TrimSpace(line[1:])), 10, 64)
	if err != nil {
		return nil, err
	}
	if x < 0 {
		return line, nil
	}
	out := make([]byte, len(line)+int(x)+2)
	if _, err := io.ReadFull(c.rd, out[len(line):]); err != nil {
		return nil, err
	}
	if !bytes.HasSuffix(out, []byte{'\r', '\n'}) {
		return nil, errors.New("invalid response")
	}
	copy(out, line)
	return out, nil
}

func (c *client) readLine() ([]byte, error) {
	line, err := c.rd.ReadBytes('\r')
	if err != nil {
		return nil, err
	}
	ch, err := c.rd.ReadByte()
	if err != nil {
		return nil, err
	}
	if ch != '\n' {
		return nil, errors.New("invalid response")
	}
	return append(line, '\n'), nil
}

func (c *client) Reader() io.Reader {
	return c.rd
}

func (c *client) readLiveResp() (message []byte, err error) {
	return c.readResp()
}

// plainToCompat converts a plain message like "SET fleet truck1 ..."  into a
// Tile38 compatible blob.
func plainToCompat(message string) []byte {
	var args []string
	// search for the beginning of the first argument
	for i := 0; i < len(message); i++ {
		if message[i] != ' ' {
			// first argument found
			if message[i] == '"' || message[i] == '\'' {
				// using a string caps
				s := i
				cap := message[i]
				for ; i < len(message); i++ {
					if message[i] == cap {
						if message[i-1] == '\\' {
							continue
						}
						if i == len(message)-1 || message[i+1] == ' ' {
							args = append(args, message[s:i+1])
							i++
							break
						}
					}
				}
			} else {
				// using plain string, terminated by a space
				s := i
				var quotes bool
				for ; i < len(message); i++ {
					if message[i] == '"' || message[i] == '\'' {
						quotes = true
					}
					if i == len(message)-1 || message[i+1] == ' ' {
						arg := message[s : i+1]
						if quotes {
							arg = strconv.Quote(arg)
						}
						args = append(args, arg)
						i++
						break
					}
				}
			}
		}
	}
	return []byte(strings.Join(args, " ") + "\r\n")
}

func clearScreen() {
	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		cmd = exec.Command("cmd", "/c", "cls")
	} else {
		cmd = exec.Command("clear")
	}
	cmd.Stdout = os.Stdout
	cmd.Run()
}


================================================
FILE: cmd/tile38-luamemtest/main.go
================================================
package main

import (
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"math"
	"runtime"
	"runtime/debug"

	"strings"

	"github.com/tidwall/resp"
	lua "github.com/yuin/gopher-lua"
)

func Sha1Sum(s string) string {
	h := sha1.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}

// Convert lua LValue to RESP value
func ConvertToResp(val lua.LValue) resp.Value {
	switch val.Type() {
	case lua.LTNil:
		return resp.NullValue()
	case lua.LTBool:
		if val == lua.LTrue {
			return resp.IntegerValue(1)
		} else {
			return resp.NullValue()
		}
	case lua.LTNumber:
		if float := float64(val.(lua.LNumber)); math.IsNaN(float) || math.IsInf(float, 0) {
			return resp.FloatValue(float)
		} else {
			return resp.IntegerValue(int(math.Floor(float)))
		}
	case lua.LTString:
		return resp.StringValue(val.String())
	case lua.LTTable:
		var values []resp.Value
		var specialValues []resp.Value
		var cb func(lk lua.LValue, lv lua.LValue)
		tbl := val.(*lua.LTable)

		if tbl.Len() != 0 { // list
			cb = func(lk lua.LValue, lv lua.LValue) {
				values = append(values, ConvertToResp(lv))
			}
		} else { // map
			cb = func(lk lua.LValue, lv lua.LValue) {
				if lk.Type() == lua.LTString {
					lks := lk.String()
					switch lks {
					case "ok":
						specialValues = append(specialValues, resp.SimpleStringValue(lv.String()))
					case "err":
						specialValues = append(specialValues, resp.ErrorValue(errors.New(lv.String())))
					}
				}
				values = append(values, resp.ArrayValue(
					[]resp.Value{ConvertToResp(lk), ConvertToResp(lv)}))
			}
		}
		tbl.ForEach(cb)
		if len(values) == 1 && len(specialValues) == 1 {
			return specialValues[0]
		}
		return resp.ArrayValue(values)
	}
	return resp.ErrorValue(errors.New("Unsupported lua type: " + val.Type().String()))
}

// Convert RESP value to lua LValue
func ConvertToLua(L *lua.LState, val resp.Value) lua.LValue {
	if val.IsNull() {
		return lua.LFalse
	}
	switch val.Type() {
	case resp.Integer:
		return lua.LNumber(val.Integer())
	case resp.BulkString:
		return lua.LString(val.String())
	case resp.Error:
		tbl := L.CreateTable(0, 1)
		tbl.RawSetString("err", lua.LString(val.String()))
		return tbl
	case resp.SimpleString:
		tbl := L.CreateTable(0, 1)
		tbl.RawSetString("ok", lua.LString(val.String()))
		return tbl
	case resp.Array:
		tbl := L.CreateTable(len(val.Array()), 0)
		for _, item := range val.Array() {
			tbl.Append(ConvertToLua(L, item))
		}
		return tbl
	}
	return lua.LString("ERR: unknown RESP type: " + val.Type().String())
}

func luaTile38Call(evalcmd string, cmd string, args ...string) (resp.Value, error) {
	var values []resp.Value
	values = append(values, resp.StringValue("RUNNING:"))
	values = append(values, resp.StringValue(evalcmd))
	values = append(values, resp.StringValue(cmd))
	for _, arg := range args {
		values = append(values, resp.StringValue(arg))
	}

	return resp.ArrayValue(values), nil
}

func NewLuaState() *lua.LState {
	L := lua.NewState()

	get_args := func(ls *lua.LState) (evalCmd string, args []string) {
		evalCmd = ls.GetGlobal("EVAL_CMD").String()
		//log.Debugf("EVAL_CMD %s\n", evalCmd)

		// Trying to work with unknown number of args.
		// When we see empty arg we call it enough.
		for i := 1; ; i++ {
			if arg := ls.ToString(i); arg == "" {
				break
			} else {
				args = append(args, arg)
			}
		}
		return
	}
	call := func(ls *lua.LState) int {
		evalCmd, args := get_args(ls)
		if res, err := luaTile38Call(evalCmd, args[0], args[1:]...); err != nil {
			//log.Debugf("RES type: %s value: %s ERR %s\n", res.Type(), res.String(), err);
			ls.RaiseError("ERR %s", err.Error())
			return 0
		} else {
			//log.Debugf("RES type: %s value: %s\n", res.Type(), res.String());
			ls.Push(ConvertToLua(ls, res))
			return 1
		}
	}
	pcall := func(ls *lua.LState) int {
		evalCmd, args := get_args(ls)
		if res, err := luaTile38Call(evalCmd, args[0], args[1:]...); err != nil {
			//log.Debugf("RES type: %s value: %s ERR %s\n", res.Type(), res.String(), err);
			ls.Push(ConvertToLua(ls, resp.ErrorValue(err)))
			return 1
		} else {
			//log.Debugf("RES type: %s value: %s\n", res.Type(), res.String());
			ls.Push(ConvertToLua(ls, res))
			return 1
		}
	}
	error_reply := func(ls *lua.LState) int {
		tbl := L.CreateTable(0, 1)
		tbl.RawSetString("err", lua.LString(ls.ToString(1)))
		ls.Push(tbl)
		return 1
	}
	status_reply := func(ls *lua.LState) int {
		tbl := L.CreateTable(0, 1)
		tbl.RawSetString("ok", lua.LString(ls.ToString(1)))
		ls.Push(tbl)
		return 1
	}
	sha1hex := func(ls *lua.LState) int {
		sha_sum := Sha1Sum(ls.ToString(1))
		ls.Push(lua.LString(sha_sum))
		return 1
	}
	var exports = map[string]lua.LGFunction{
		"call":         call,
		"pcall":        pcall,
		"error_reply":  error_reply,
		"status_reply": status_reply,
		"sha1hex":      sha1hex,
	}
	L.SetGlobal("tile38", L.SetFuncs(L.NewTable(), exports))
	return L
}

func makeSafeErr(err error) error {
	return errors.New(strings.Replace(err.Error(), "\n", `\n`, -1))
}

func runLuaFunc(luaState *lua.LState, script string, name string) resp.Value {
	luaState.SetGlobal("EVAL_CMD", lua.LString("FAKE_EVAL"))
	fn, err := luaState.Load(strings.NewReader(script), name)
	if err != nil {
		return resp.ErrorValue(makeSafeErr(err))
	}
	luaState.Push(fn)
	if err := luaState.PCall(0, 1, nil); err != nil {
		return resp.ErrorValue(makeSafeErr(err))
	}
	ret := luaState.Get(-1) // returned value
	luaState.Pop(1)
	luaState.SetGlobal("EVAL_CMD", lua.LNil)
	return ConvertToResp(ret)
}

func runMany(luaState *lua.LState, start int, num int) int {
	fmt.Printf("\nRunning %d lua calls... ", num)
	for i := 0; i < num; i++ {
		script := fmt.Sprintf("return tile38.call('foo', 'bar', %d)", i)
		name := fmt.Sprintf("f_%020d", i)
		ret := runLuaFunc(luaState, script, name)
		if ret.Type() == resp.Error {
			panic(ret.String())
		}
	}
	fmt.Printf("done.\n")
	return start + num
}

func printMemStats() {
	var mem runtime.MemStats
	runtime.GC()
	debug.FreeOSMemory()
	runtime.GC()
	debug.FreeOSMemory()
	runtime.GC()
	debug.FreeOSMemory()
	runtime.GC()
	debug.FreeOSMemory()
	runtime.ReadMemStats(&mem)
	fmt.Printf("MemStats:  Alloc %d, HeapAlloc %d, HeapSys %d, GCSys %d, HeapObjects %d.\n",
		mem.Alloc, mem.HeapAlloc, mem.HeapSys, mem.GCSys, mem.HeapObjects)
}

func testLua() {
	var luaState *lua.LState
	start := 12345
	luaState = NewLuaState()

	printMemStats()

	fmt.Printf("\nRunning single call as a test\n")
	ret := runLuaFunc(luaState, "return tile38.call('fake_cmd', 'a', 'b')", "test_call")
	fmt.Printf("Result: %s\n", ret.String())

	printMemStats()

	start = runMany(luaState, start, 100)
	printMemStats()

	start = runMany(luaState, start, 100)
	printMemStats()

	start = runMany(luaState, start, 100)
	printMemStats()

	start = runMany(luaState, start, 100)
	printMemStats()

	start = runMany(luaState, start, 1000)
	printMemStats()

	start = runMany(luaState, start, 10000)
	printMemStats()

	start = runMany(luaState, start, 1000)
	printMemStats()

	start = runMany(luaState, start, 100)
	printMemStats()

	_ = runMany(luaState, start, 1000)
	printMemStats()

	luaState.Close()
}

func main() {
	fmt.Printf("Starting memtest.\n")
	testLua()
}


================================================
FILE: cmd/tile38-server/main.go
================================================
package main

import (
	"flag"
	"fmt"
	"io"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"sync"
	"syscall"

	"github.com/tidwall/gjson"
	"github.com/tidwall/tile38/core"
	"github.com/tidwall/tile38/internal/hservice"
	"github.com/tidwall/tile38/internal/log"
	"github.com/tidwall/tile38/internal/server"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

// TODO: Set to false in 2.*
var httpTransport = true

////////////////////////////////////////////////////////////////////////////////
//
// Fire up a webhook test server by using the --webhook-http-consumer-port
// for example
//   $ ./tile38-server --webhook-http-consumer-port 9999
//
// The create hooks like such...
//   SETHOOK myhook http://localhost:9999/myhook NEARBY mykey FENCE POINT 33.5 -115.5 1000
//
////////////////////////////////////////////////////////////////////////////////
//
// Memory profiling - start the server with the -pprofport flag
//
//   $ ./tile38-server -pprofport 6060
//
// Then, at any point, from a different terminal execute:
//   $ go tool pprof -svg http://localhost:6060/debug/pprof/heap > out.svg
//
// Load the SVG into a web browser to visualize the memory usage
//
////////////////////////////////////////////////////////////////////////////////

type hserver struct{}

func (s *hserver) Send(ctx context.Context, in *hservice.MessageRequest) (*hservice.MessageReply, error) {
	return &hservice.MessageReply{Ok: true}, nil
}

func main() {
	gitsha := " (" + core.GitSHA + ")"
	if gitsha == " (0000000)" {
		gitsha = ""
	}
	versionLine := `tile38-server version: ` + core.Version + gitsha

	output := os.Stderr
	flag.Usage = func() {
		fmt.Fprintf(output,
			"%s", versionLine+`

Usage: tile38-server [-p port]

Basic Options:
  -h hostname : listening host
  -p port     : listening port (default: 9851)
  -d path     : data directory (default: data)
  -s socket   : listen on unix socket file
  -l encoding : set log encoding to json or text (default: text) 
  -o output   : auto set client output to json or resp (default: resp) 
  -q          : no logging. totally silent output
  -v          : enable verbose logging
  -vv         : enable very verbose logging

Advanced Options: 
  --pidfile path          : file that contains the pid
  --appendonly yes/no     : AOF persistence (default: yes)
  --appendfilename path   : AOF path (default: data/appendonly.aof)
  --queuefilename path    : Event queue path (default:data/queue.db)
  --http-transport yes/no : HTTP transport (default: yes)
  --protected-mode yes/no : protected mode (default: yes)
  --nohup                 : do not exit on SIGHUP
  --spinlock              : use a spinlock. For very write-heavy workloads

Developer Options:
  --dev                             : enable developer mode
  --webhook-http-consumer-port port : Start a test HTTP webhook server
  --webhook-grpc-consumer-port port : Start a test GRPC webhook server

`,
		)
	}

	if len(os.Args) == 3 && os.Args[1] == "--webhook-http-consumer-port" {
		log.SetOutput(os.Stderr)
		port, err := strconv.ParseUint(os.Args[2], 10, 16)
		if err != nil {
			log.Fatal(err)
		}
		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			data, err := io.ReadAll(r.Body)
			if err != nil {
				log.Fatal(err)
			}
			log.HTTPf("http: %s : %s", r.URL.Path, string(data))
		})
		log.Infof("webhook server http://localhost:%d/", port)
		if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
			log.Fatal(err)
		}
		return
	}

	if len(os.Args) == 3 && os.Args[1] == "--webhook-grpc-consumer-port" {
		log.SetOutput(os.Stderr)
		port, err := strconv.ParseUint(os.Args[2], 10, 16)
		if err != nil {
			log.Fatal(err)
		}

		lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
		if err != nil {
			log.Fatal(err)
		}
		s := grpc.NewServer()
		hservice.RegisterHookServiceServer(s, &hserver{})
		log.Infof("webhook server grpc://localhost:%d/", port)
		if err := s.Serve(lis); err != nil {
			log.Fatal(err)
		}
		return
	}

	var (
		nohup               bool
		showEvioDisabled    bool
		showThreadsDisabled bool
		spinlock            bool
	)

	var (
		// use to be in core/options.go

		// DevMode puts application in to dev mode
		devMode = false

		// ShowDebugMessages allows for log.Debug to print to console.
		showDebugMessages = false

		// ProtectedMode forces Tile38 to default in protected mode.
		protectedMode = "no"

		// AppendOnly allows for disabling the appendonly file.
		appendOnly = true

		// AppendFileName allows for custom appendonly file path
		appendFileName = ""

		// QueueFileName allows for custom queue.db file path
		queueFileName = ""

		// ClientOutput for auto assigning the output for client.
		clientOutput = ""
	)

	// parse non standard args.
	nargs := []string{os.Args[0]}
	for i := 1; i < len(os.Args); i++ {
		switch os.Args[i] {
		case "--help":
			output = os.Stdout
			flag.Usage()
			return
		case "--version":
			fmt.Fprintf(os.Stdout, "%s\n", versionLine)
			return
		case "--protected-mode", "-protected-mode":
			i++
			if i < len(os.Args) {
				switch strings.ToLower(os.Args[i]) {
				case "no":
					protectedMode = "no"
					continue
				case "yes":
					protectedMode = "yes"
					continue
				}
			}
			fmt.Fprintf(os.Stderr, "protected-mode must be 'yes' or 'no'\n")
			os.Exit(1)
		case "--dev", "-dev":
			devMode = true
			continue
		case "--nohup", "-nohup":
			nohup = true
			continue
		case "--spinlock", "-spinlock":
			spinlock = true
			continue
		case "--appendonly", "-appendonly":
			i++
			if i < len(os.Args) {
				switch strings.ToLower(os.Args[i]) {
				case "no":
					appendOnly = false
					continue
				case "yes":
					appendOnly = true
					continue
				}
			}
			fmt.Fprintf(os.Stderr, "appendonly must be 'yes' or 'no'\n")
			os.Exit(1)
		case "--appendfilename", "-appendfilename":
			i++
			if i == len(os.Args) || os.Args[i] == "" {
				fmt.Fprintf(os.Stderr, "appendfilename must have a value\n")
				os.Exit(1)
			}
			appendFileName = os.Args[i]
		case "--queuefilename", "-queuefilename":
			i++
			if i == len(os.Args) || os.Args[i] == "" {
				fmt.Fprintf(os.Stderr, "queuefilename must have a value\n")
				os.Exit(1)
			}
			queueFileName = os.Args[i]
		case "-o":
			i++
			if i < len(os.Args) {
				switch strings.ToLower(os.Args[i]) {
				case "resp", "json":
					clientOutput = strings.ToLower(os.Args[i])
					continue
				}
			}
			fmt.Fprintf(os.Stderr, "output must be 'resp' or 'json'\n")
			os.Exit(1)
		case "--http-transport", "-http-transport":
			i++
			if i < len(os.Args) {
				switch strings.ToLower(os.Args[i]) {
				case "1", "true", "yes":
					httpTransport = true
					continue
				case "0", "false", "no":
					httpTransport = false
					continue
				}
			}
			fmt.Fprintf(os.Stderr, "http-transport must be 'yes' or 'no'\n")
			os.Exit(1)
		case "--threads", "-threads":
			i++
			if i < len(os.Args) {
				_, err := strconv.ParseUint(os.Args[i], 10, 16)
				if err != nil {
					fmt.Fprintf(os.Stderr, "threads must be a valid number\n")
					os.Exit(1)
				}
				showThreadsDisabled = true
				continue
			}
			fmt.Fprintf(os.Stderr, "threads must be a valid number \n")
			os.Exit(1)
		case "--evio", "-evio":
			i++
			if i < len(os.Args) {
				switch strings.ToLower(os.Args[i]) {
				case "no", "yes":
					showEvioDisabled = true
					continue
				}
			}
			fmt.Fprintf(os.Stderr, "evio must be 'yes' or 'no'\n")
			os.Exit(1)
		default:
			nargs = append(nargs, os.Args[i])
		}
	}
	os.Args = nargs

	metricsAddr := flag.String("metrics-addr", "", "The listening addr for Prometheus metrics.")

	var (
		dir         string
		port        int
		host        string
		unixSocket  string
		verbose     bool
		veryVerbose bool
		logEncoding string
		quiet       bool
		pidfile     string
		cpuprofile  string
		memprofile  string
		pprofport   int
	)

	flag.IntVar(&port, "p", 9851, "The listening port")
	flag.StringVar(&pidfile, "pidfile", "", "A file that contains the pid")
	flag.StringVar(&host, "h", "", "The listening host")
	flag.StringVar(&unixSocket, "s", "", "Listen on a unix socket")
	flag.StringVar(&dir, "d", "data", "The data directory")
	flag.StringVar(&logEncoding, "l", "text", "The log encoding json or text (default: text)")
	flag.BoolVar(&verbose, "v", false, "Enable verbose logging")
	flag.BoolVar(&quiet, "q", false, "Quiet logging. Totally silent")
	flag.BoolVar(&veryVerbose, "vv", false, "Enable very verbose logging")
	flag.IntVar(&pprofport, "pprofport", 0, "pprofport http at port")
	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
	flag.Parse()

	if logEncoding == "json" {
		log.SetLogJSON(true)
		data, _ := os.ReadFile(filepath.Join(dir, "config"))
		if gjson.GetBytes(data, "logconfig.encoding").String() == "json" {
			c := gjson.GetBytes(data, "logconfig").String()
			log.Build(c)
		} else {
			log.Build("")
		}
	}

	var logw io.Writer = os.Stderr
	if quiet {
		logw = io.Discard
	}

	log.SetOutput(logw)

	if quiet {
		log.SetLevel(0)
	} else if veryVerbose {
		log.SetLevel(3)
	} else if verbose {
		log.SetLevel(2)
	} else {
		log.SetLevel(1)
	}

	showDebugMessages = veryVerbose

	hostd := ""
	if host != "" {
		hostd = "Addr: " + host + ", "
	}

	// pprof
	if cpuprofile != "" {
		log.Debugf("cpuprofile active")
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
	}
	if memprofile != "" {
		log.Debug("memprofile active")
	}

	var pprofcleanedup bool
	var pprofcleanupMu sync.Mutex
	pprofcleanup := func() {
		pprofcleanupMu.Lock()
		defer pprofcleanupMu.Unlock()
		if pprofcleanedup {
			return
		}
		// cleanup code
		if cpuprofile != "" {
			pprof.StopCPUProfile()
		}
		if memprofile != "" {
			f, err := os.Create(memprofile)
			if err != nil {
				log.Fatal("could not create memory profile: ", err)
			}
			runtime.GC() // get up-to-date statistics
			if err := pprof.WriteHeapProfile(f); err != nil {
				log.Fatal("could not write memory profile: ", err)
			}
			f.Close()
		}
		pprofcleanedup = true
	}
	defer pprofcleanup()

	if pprofport != 0 {
		log.Debugf("pprof http at port %d", pprofport)
		go func() {
			log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", pprofport), nil))
		}()
	}

	if unixSocket != "" {
		port = 0
	}

	// pid file
	var pidferr error
	var pidcleanedup bool
	var pidcleanupMu sync.Mutex
	pidcleanup := func() {
		if pidfile != "" {
			pidcleanupMu.Lock()
			defer pidcleanupMu.Unlock()
			if pidcleanedup {
				return
			}
			// cleanup code
			if pidfile != "" {
				os.Remove(pidfile)
			}
			pidcleanedup = true
		}
	}
	defer pidcleanup()
	if pidfile != "" {
		os.WriteFile(pidfile, []byte(fmt.Sprintf("%d\n", os.Getpid())), 0666)
	}

	c := make(chan os.Signal, 1)
	shutdown := make(chan bool, 1)

	signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
	go func() {
		for s := range c {
			if s == syscall.SIGHUP && nohup {
				continue
			}
			log.Warnf("signal: %v", s)
			pidcleanup()
			pprofcleanup()
			switch {
			default:
				os.Exit(-1)
			case s == syscall.SIGHUP:
				os.Exit(1)
			case s == syscall.SIGINT:
				os.Exit(2)
			case s == syscall.SIGQUIT:
				os.Exit(3)
			case s == syscall.SIGTERM:
				shutdown <- true
			}
		}
	}()

	var saddr string
	if unixSocket != "" {
		saddr = fmt.Sprintf("Socket: %s", unixSocket)
	} else {
		saddr = fmt.Sprintf("Port: %d", port)
	}

	if log.LogJSON() {
		log.Printf(`Tile38 %s%s %d bit (%s/%s) %s%s, PID: %d. Visit tile38.com/sponsor to support the project`,
			core.Version, gitsha, strconv.IntSize, runtime.GOARCH, runtime.GOOS, hostd, saddr, os.Getpid())
	} else {
		fmt.Fprintf(logw, `
   _____ _ _     ___ ___
  |_   _|_| |___|_  | . |  Tile38 %s%s %d bit (%s/%s)
    | | | | | -_|_  | . |  %s%s, PID: %d
    |_| |_|_|___|___|___|  tile38.com

`, core.Version, gitsha, strconv.IntSize, runtime.GOARCH, runtime.GOOS, hostd,
			saddr, os.Getpid())
	}

	if pidferr != nil {
		log.Warnf("pidfile: %v", pidferr)
	}
	if showEvioDisabled {
		log.Warnf("evio is not currently supported")
	}
	if showThreadsDisabled {
		log.Warnf("thread flag is deprecated use GOMAXPROCS to set number of threads instead")
	}
	opts := server.Options{
		Host:              host,
		Port:              port,
		Dir:               dir,
		UseHTTP:           httpTransport,
		MetricsAddr:       *metricsAddr,
		UnixSocketPath:    unixSocket,
		DevMode:           devMode,
		ShowDebugMessages: showDebugMessages,
		ProtectedMode:     protectedMode,
		AppendOnly:        appendOnly,
		AppendFileName:    appendFileName,
		QueueFileName:     queueFileName,
		Shutdown:          shutdown,
		Spinlock:          spinlock,
		ClientOutput:      clientOutput,
	}
	if err := server.Serve(opts); err != nil {
		log.Fatal(err)
	}
}


================================================
FILE: core/commands.go
================================================
//go:build ignore

package core

import (
	"encoding/json"
	"strings"
)

const (
	clear  = "\x1b[0m"
	bright = "\x1b[1m"
	gray   = "\x1b[90m"
	yellow = "\x1b[33m"
)

// Command represents a Tile38 command.
type Command struct {
	Name       string     `json:"-"`
	Summary    string     `json:"summary"`
	Complexity string     `json:"complexity"`
	Arguments  []Argument `json:"arguments"`
	Since      string     `json:"since"`
	Group      string     `json:"group"`
	DevOnly    bool       `json:"dev"`
}

// String returns a string representation of the command.
func (c Command) String() string {
	var s = c.Name
	for _, arg := range c.Arguments {
		s += " " + arg.String()
	}
	return s
}

// TermOutput returns a string representation of the command suitable for displaying in a terminal.
func (c Command) TermOutput(indent string) string {
	line := c.String()
	var line1 string
	if strings.HasPrefix(line, c.Name) {
		line1 = bright + c.Name + clear + gray + line[len(c.Name):] + clear
	} else {
		line1 = bright + strings.Replace(c.String(), " ", " "+clear+gray, 1) + clear
	}
	line2 := yellow + "summary: " + clear + c.Summary
	//line3 := yellow + "since: " + clear + c.Since
	return indent + line1 + "\n" + indent + line2 + "\n" //+ indent + line3 + "\n"
}

// EnumArg represents a enum arguments.
type EnumArg struct {
	Name      string     `json:"name"`
	Arguments []Argument `json:"arguments"`
}

// String returns a string representation of an EnumArg.
func (a EnumArg) String() string {
	var s = a.Name
	for _, arg := range a.Arguments {
		s += " " + arg.String()
	}
	return s
}

// Argument represents a command argument.
type Argument struct {
	Command  string      `json:"command"`
	NameAny  interface{} `json:"name"`
	TypeAny  interface{} `json:"type"`
	Optional bool        `json:"optional"`
	Multiple bool        `json:"multiple"`
	Variadic bool        `json:"variadic"`
	Enum     []string    `json:"enum"`
	EnumArgs []EnumArg   `json:"enumargs"`
}

// String returns a string representation of an Argument.
func (a Argument) String() string {
	var s string
	if a.Command != "" {
		s += " " + a.Command
	}
	if len(a.EnumArgs) > 0 {
		eargs := ""
		for _, arg := range a.EnumArgs {
			v := arg.String()
			if strings.Contains(v, " ") {
				v = "(" + v + ")"
			}
			eargs += v + "|"
		}
		if len(eargs) > 0 {
			eargs = eargs[:len(eargs)-1]
		}
		s += " " + eargs
	} else if len(a.Enum) > 0 {
		s += " " + strings.Join(a.Enum, "|")
	} else {
		names, _ := a.NameTypes()
		subs := ""
		for _, name := range names {
			subs += " " + name
		}
		subs = strings.TrimSpace(subs)
		s += " " + subs
		if a.Variadic {
			if len(names) == 0 {
				s += " [" + subs + " ...]"
			} else {
				s += " [" + names[len(names)-1] + " ...]"
			}
		}
		if a.Multiple {
			s += " ..."
		}
	}
	s = strings.TrimSpace(s)
	if a.Optional {
		s = "[" + s + "]"
	}
	return s
}

func parseAnyStringArray(any interface{}) []string {
	if str, ok := any.(string); ok {
		return []string{str}
	} else if any, ok := any.([]interface{}); ok {
		arr := []string{}
		for _, any := range any {
			if str, ok := any.(string); ok {
				arr = append(arr, str)
			}
		}
		return arr
	}
	return []string{}
}

// NameTypes returns the types and names of an argument as separate arrays.
func (a Argument) NameTypes() (names, types []string) {
	names = parseAnyStringArray(a.NameAny)
	types = parseAnyStringArray(a.TypeAny)
	if len(types) > len(names) {
		types = types[:len(names)]
	} else {
		for len(types) < len(names) {
			types = append(types, "")
		}
	}
	return
}

// Commands is a map of all of the commands.
var Commands = func() map[string]Command {
	var commands map[string]Command
	if err := json.Unmarshal([]byte(commandsJSON), &commands); err != nil {
		panic(err.Error())
	}
	for name, command := range commands {
		command.Name = strings.ToUpper(name)
		commands[name] = command
	}
	return commands
}()

var commandsJSON = `{{.CommandsJSON}}`


================================================
FILE: core/commands.json
================================================
{
  "SET": {
    "summary": "Sets the value of an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "command": "FIELD",
        "name": ["name", "value"],
        "type": ["string", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "EX",
        "name": ["seconds"],
        "type": ["double"],
        "optional": true,
        "multiple": false
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "NX"
          },
          {
            "name": "XX"
          }
        ]
      },
      {
        "name": "value",
        "enumargs": [
          {
            "name": "OBJECT",
            "arguments": [
              {
                "name": "geojson",
                "type": "geojson"
              }
            ]
          },
          {
            "name": "POINT",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "z",
                "type": "double",
                "optional": true
              }
            ]
          },
          {
            "name": "BOUNDS",
            "arguments": [
              {
                "name": "minlat",
                "type": "double"
              },
              {
                "name": "minlon",
                "type": "double"
              },
              {
                "name": "maxlat",
                "type": "double"
              },
              {
                "name": "maxlon",
                "type": "double"
              }
            ]
          },
          {
            "name": "HASH",
            "arguments": [
              {
                "name": "geohash",
                "type": "geohash"
              }
            ]
          },
          {
            "name": "STRING",
            "arguments": [
              {
                "name": "value",
                "type": "string"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "EXPIRE": {
    "summary": "Set a timeout on an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "seconds",
        "type": "double"
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "TTL": {
    "summary": "Get a timeout on an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "EXISTS": {
    "summary": "Checks to see if a id exists",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      }
    ],
    "since": "1.33.0",
    "group": "keys"
  },
  "FEXISTS": {
    "summary": "Checks to see if a field exists on a id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "field",
        "type": "string"
      }
    ],
    "since": "1.33.0",
    "group": "keys"
  },
  "PERSIST": {
    "summary": "Remove the existing timeout on an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "FSET": {
    "summary": "Set the value for one or more fields of an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "command": "XX",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "name": ["field", "value"],
        "type": ["string", "double"]
      },
      {
        "name": ["field", "value"],
        "type": ["string", "double"],
        "multiple": true,
        "optional": true
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "FGET": {
    "summary": "Gets the value for the field of an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "field",
        "type": "string"
      }
    ],
    "since": "1.33.0",
    "group": "keys"
  },
  "BOUNDS": {
    "summary": "Get the combined bounds of all the objects in a key",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      }
    ],
    "since": "1.3.0",
    "group": "keys"
  },
  "GET": {
    "summary": "Get the object of an id",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "command": "WITHFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "OBJECT"
          },
          {
            "name": "POINT"
          },
          {
            "name": "BOUNDS"
          },
          {
            "name": "HASH",
            "arguments": [
              {
                "name": "geohash",
                "type": "geohash"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "DEL": {
    "summary": "Delete an id from a key",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "command": "ERRON404",
        "name": [],
        "type": [],
        "optional": true
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "DROP": {
    "summary": "Remove a key from the database",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "RENAME": {
    "summary": "Rename a key to be stored under a different name.",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "newkey",
        "type": "string"
      }
    ],
    "since": "1.14.5",
    "group": "keys"
  },
  "RENAMENX": {
    "summary": "Rename a key to be stored under a different name, if a new key does not exist.",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "newkey",
        "type": "string"
      }
    ],
    "since": "1.14.5",
    "group": "keys"
  },
  "KEYS": {
    "summary": "Finds all keys matching the given pattern",
    "complexity": "O(N) where N is the number of keys in the database",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "STATS": {
    "summary": "Show stats for one or more keys",
    "complexity": "O(N) where N is the number of keys being requested",
    "arguments": [
      {
        "name": "key",
        "type": "string",
        "variadic": true
      }
    ],
    "since": "1.0.0",
    "group": "keys"
  },
  "SEARCH": {
    "summary": "Search for string values in a key",
    "complexity": "O(N) where N is the number of values in the key",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "CURSOR",
        "name": "start",
        "type": "integer",
        "optional": true
      },
      {
        "command": "LIMIT",
        "name": "count",
        "type": "integer",
        "optional": true
      },
      {
        "command": "MATCH",
        "name": "pattern",
        "type": "pattern",
        "optional": true
      },
      {
        "name": "order",
        "optional": true,
        "enumargs": [
          {
            "name": "ASC"
          },
          {
            "name": "DESC"
          }
        ]
      },
      {
        "command": "WHERE",
        "name": ["field", "min", "max"],
        "type": ["string", "double", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "WHEREIN",
        "name": ["field", "count", "value"],
        "type": ["string", "integer", "double"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVAL",
        "name": ["script", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVALSHA",
        "name": ["sha1", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "NOFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "COUNT"
          },
          {
            "name": "IDS"
          }
        ]
      }
    ],
    "since": "1.4.2",
    "group": "search"
  },
  "SCAN": {
    "summary": "Incrementally iterate though a key",
    "complexity": "O(N) where N is the number of ids in the key",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "CURSOR",
        "name": "start",
        "type": "integer",
        "optional": true
      },
      {
        "command": "LIMIT",
        "name": "count",
        "type": "integer",
        "optional": true
      },
      {
        "command": "MATCH",
        "name": "pattern",
        "type": "pattern",
        "optional": true
      },
      {
        "name": "order",
        "optional": true,
        "enumargs": [
          {
            "name": "ASC"
          },
          {
            "name": "DESC"
          }
        ]
      },
      {
        "command": "WHERE",
        "name": ["field", "min", "max"],
        "type": ["string", "double", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "WHEREIN",
        "name": ["field", "count", "value"],
        "type": ["string", "integer", "double"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVAL",
        "name": ["script", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVALSHA",
        "name": ["sha1", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "NOFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "COUNT"
          },
          {
            "name": "IDS"
          },
          {
            "name": "OBJECTS"
          },
          {
            "name": "POINTS"
          },
          {
            "name": "BOUNDS"
          },
          {
            "name": "HASHES",
            "arguments": [
              {
                "name": "precision",
                "type": "integer"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "search"
  },
  "NEARBY": {
    "summary": "Searches for ids that are nearby a point",
    "complexity": "O(log(N)) where N is the number of ids in the area",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "CURSOR",
        "name": "start",
        "type": "integer",
        "optional": true
      },
      {
        "command": "LIMIT",
        "name": "count",
        "type": "integer",
        "optional": true
      },
      {
        "command": "MATCH",
        "name": "pattern",
        "type": "pattern",
        "optional": true
      },
      {
        "command": "DISTANCE",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "WHERE",
        "name": ["field", "min", "max"],
        "type": ["string", "double", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "WHEREIN",
        "name": ["field", "count", "value"],
        "type": ["string", "integer", "double"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVAL",
        "name": ["script", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVALSHA",
        "name": ["sha1", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "NOFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "FENCE",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "DETECT",
        "name": ["what"],
        "type": ["string"],
        "optional": true
      },
      {
        "command": "COMMANDS",
        "name": ["which"],
        "type": ["string"],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "COUNT"
          },
          {
            "name": "IDS"
          },
          {
            "name": "OBJECTS"
          },
          {
            "name": "POINTS"
          },
          {
            "name": "BOUNDS"
          },
          {
            "name": "HASHES",
            "arguments": [
              {
                "name": "precision",
                "type": "integer"
              }
            ]
          }
        ]
      },
      {
        "name": "area",
        "enumargs": [
          {
            "name": "POINT",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "meters",
                "type": "double"
              }
            ]
          },
          {
            "name": "ROAM",
            "arguments": [
              {
                "name": "key",
                "type": "string"
              },
              {
                "name": "pattern",
                "type": "pattern"
              },
              {
                "name": "meters",
                "type": "double"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "search"
  },
  "WITHIN": {
    "summary": "Searches for ids that completely within the area",
    "complexity": "O(log(N)) where N is the number of ids in the area",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "CURSOR",
        "name": "start",
        "type": "integer",
        "optional": true
      },
      {
        "command": "LIMIT",
        "name": "count",
        "type": "integer",
        "optional": true
      },
      {
        "command": "MATCH",
        "name": "pattern",
        "type": "pattern",
        "optional": true
      },
      {
        "command": "WHERE",
        "name": ["field", "min", "max"],
        "type": ["string", "double", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "WHEREIN",
        "name": ["field", "count", "value"],
        "type": ["string", "integer", "double"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVAL",
        "name": ["script", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVALSHA",
        "name": ["sha1", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "NOFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "FENCE",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "DETECT",
        "name": ["what"],
        "type": ["string"],
        "optional": true
      },
      {
        "command": "COMMANDS",
        "name": ["which"],
        "type": ["string"],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "COUNT"
          },
          {
            "name": "IDS"
          },
          {
            "name": "OBJECTS"
          },
          {
            "name": "POINTS"
          },
          {
            "name": "BOUNDS"
          },
          {
            "name": "HASHES",
            "arguments": [
              {
                "name": "precision",
                "type": "integer"
              }
            ]
          }
        ]
      },
      {
        "name": "area",
        "enumargs": [
          {
            "name": "GET",
            "arguments": [
              {
                "name": "key",
                "type": "string"
              },
              {
                "name": "id",
                "type": "string"
              }
            ]
          },
          {
            "name": "BOUNDS",
            "arguments": [
              {
                "name": "minlat",
                "type": "double"
              },
              {
                "name": "minlon",
                "type": "double"
              },
              {
                "name": "maxlat",
                "type": "double"
              },
              {
                "name": "maxlon",
                "type": "double"
              }
            ]
          },
          {
            "name": "OBJECT",
            "arguments": [
              {
                "name": "geojson",
                "type": "geojson"
              }
            ]
          },
          {
            "name": "CIRCLE",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "meters",
                "type": "double"
              }
            ]
          },
          {
            "name": "TILE",
            "arguments": [
              {
                "name": "x",
                "type": "double"
              },
              {
                "name": "y",
                "type": "double"
              },
              {
                "name": "z",
                "type": "double"
              }
            ]
          },
          {
            "name": "QUADKEY",
            "arguments": [
              {
                "name": "quadkey",
                "type": "string"
              }
            ]
          },
          {
            "name": "HASH",
            "arguments": [
              {
                "name": "geohash",
                "type": "geohash"
              }
            ]
          },          
          {
            "name": "SECTOR",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "radius",
                "type": "double"
              },
              {
                "name": "startBearing",
                "type": "double"
              },
              {
                "name": "endBearing",
                "type": "double"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "search"
  },
  "INTERSECTS": {
    "summary": "Searches for ids that intersect an area",
    "complexity": "O(log(N)) where N is the number of ids in the area",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "CURSOR",
        "name": "start",
        "type": "integer",
        "optional": true
      },
      {
        "command": "LIMIT",
        "name": "count",
        "type": "integer",
        "optional": true
      },
      {
        "command": "MATCH",
        "name": "pattern",
        "type": "pattern",
        "optional": true
      },
      {
        "command": "WHERE",
        "name": ["field", "min", "max"],
        "type": ["string", "double", "double"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "WHEREIN",
        "name": ["field", "count", "value"],
        "type": ["string", "integer", "double"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVAL",
        "name": ["script", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "WHEREEVALSHA",
        "name": ["sha1", "numargs", "arg"],
        "type": ["string", "integer", "string"],
        "optional": true,
        "multiple": true,
        "variadic": true
      },
      {
        "command": "CLIP",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "NOFIELDS",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "FENCE",
        "name": [],
        "type": [],
        "optional": true
      },
      {
        "command": "DETECT",
        "name": ["what"],
        "type": ["string"],
        "optional": true
      },
      {
        "command": "COMMANDS",
        "name": ["which"],
        "type": ["string"],
        "optional": true
      },
      {
        "name": "type",
        "optional": true,
        "enumargs": [
          {
            "name": "COUNT"
          },
          {
            "name": "IDS"
          },
          {
            "name": "OBJECTS"
          },
          {
            "name": "POINTS"
          },
          {
            "name": "BOUNDS"
          },
          {
            "name": "HASHES",
            "arguments": [
              {
                "name": "precision",
                "type": "integer"
              }
            ]
          }
        ]
      },
      {
        "name": "area",
        "enumargs": [
          {
            "name": "GET",
            "arguments": [
              {
                "name": "key",
                "type": "string"
              },
              {
                "name": "id",
                "type": "string"
              }
            ]
          },
          {
            "name": "BOUNDS",
            "arguments": [
              {
                "name": "minlat",
                "type": "double"
              },
              {
                "name": "minlon",
                "type": "double"
              },
              {
                "name": "maxlat",
                "type": "double"
              },
              {
                "name": "maxlon",
                "type": "double"
              }
            ]
          },
          {
            "name": "OBJECT",
            "arguments": [
              {
                "name": "geojson",
                "type": "geojson"
              }
            ]
          },
          {
            "name": "CIRCLE",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "meters",
                "type": "double"
              }
            ]
          },
          {
            "name": "TILE",
            "arguments": [
              {
                "name": "x",
                "type": "double"
              },
              {
                "name": "y",
                "type": "double"
              },
              {
                "name": "z",
                "type": "double"
              }
            ]
          },
          {
            "name": "QUADKEY",
            "arguments": [
              {
                "name": "quadkey",
                "type": "string"
              }
            ]
          },
          {
            "name": "HASH",
            "arguments": [
              {
                "name": "geohash",
                "type": "geohash"
              }
            ]
          },
          {
            "name": "SECTOR",
            "arguments": [
              {
                "name": "lat",
                "type": "double"
              },
              {
                "name": "lon",
                "type": "double"
              },
              {
                "name": "radius",
                "type": "double"
              },
              {
                "name": "startBearing",
                "type": "double"
              },
              {
                "name": "endBearing",
                "type": "double"
              }
            ]
          }
        ]
      }
    ],
    "since": "1.0.0",
    "group": "search"
  },
  "CONFIG GET": {
    "summary": "Get the value of a configuration parameter",
    "arguments": [
      {
        "name": "parameter",
        "type": "string"
      }
    ],
    "group": "server"
  },
  "CONFIG SET": {
    "summary": "Set a configuration parameter to the given value",
    "arguments": [
      {
        "name": "parameter",
        "type": "string"
      },
      {
        "name": "value",
        "type": "string",
        "optional": true
      }
    ],
    "group": "server"
  },
  "CONFIG REWRITE": {
    "summary": "Rewrite the configuration file with the in memory configuration",
    "arguments": [],
    "group": "server"
  },
  "SERVER": {
    "summary": "Show server stats and details",
    "complexity": "O(1)",
    "arguments": [],
    "since": "1.0.0",
    "group": "server"
  },
  "GC": {
    "summary": "Forces a garbage collection",
    "complexity": "O(1)",
    "arguments": [],
    "since": "1.0.0",
    "group": "server"
  },
  "READONLY": {
    "summary": "Turns on or off readonly mode",
    "complexity": "O(1)",
    "arguments": [
      {
        "enum": ["yes", "no"]
      }
    ],
    "since": "1.0.0",
    "group": "server"
  },
  "FLUSHDB": {
    "summary": "Removes all keys",
    "complexity": "O(1)",
    "arguments": [],
    "since": "1.0.0",
    "group": "server"
  },
  "FOLLOW": {
    "summary": "Follows a leader host",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "host",
        "type": "string"
      },
      {
        "name": "port",
        "type": "integer"
      }
    ],
    "since": "1.0.0",
    "group": "replication"
  },
  "AOF": {
    "summary": "Downloads the AOF starting from pos and keeps the connection alive",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "pos",
        "type": "integer"
      }
    ],
    "since": "1.0.0",
    "group": "replication"
  },
  "AOFMD5": {
    "summary": "Performs a checksum on a portion of the aof",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "pos",
        "type": "integer"
      },
      {
        "name": "size",
        "type": "integer"
      }
    ],
    "since": "1.0.0",
    "group": "replication"
  },
  "AOFSHRINK": {
    "summary": "Shrinks the aof in the background",
    "group": "replication"
  },
  "PING": {
    "summary": "Ping the server",
    "group": "connection"
  },
  "QUIT": {
    "summary": "Close the connection",
    "group": "connection"
  },
  "AUTH": {
    "summary": "Authenticate to the server",
    "arguments": [
      {
        "name": "password",
        "type": "string"
      }
    ],
    "group": "connection"
  },
  "OUTPUT": {
    "summary": "Gets or sets the output format for the current connection.",
    "arguments": [
      {
        "name": "format",
        "optional": true,
        "enumargs": [
          {
            "name": "json"
          },
          {
            "name": "resp"
          }
        ]
      }
    ],
    "group": "connection"
  },
  "TIMEOUT": {
    "summary": "Runs the following command with the timeout",
    "arguments": [
      {
        "name": "seconds",
        "type": "double"
      },
      {
        "name": "COMMAND",
        "type": "string"
      },
      {
        "command": "arg",
        "type": "string",
        "multiple": true,
        "optional": true
      }
    ],
    "group": "connection"
  },
  "SETHOOK": {
    "summary": "Creates a webhook which points to geofenced search",
    "arguments": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "endpoint",
        "type": "string"
      },
      {
        "command": "META",
        "name": ["name", "value"],
        "type": ["string", "string"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "EX",
        "name": ["seconds"],
        "type": ["double"],
        "optional": true,
        "multiple": false
      },
      {
        "enum": ["NEARBY", "WITHIN", "INTERSECTS"]
      },
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "FENCE",
        "name": [],
        "type": []
      },
      {
        "command": "DETECT",
        "name": ["what"],
        "type": ["string"],
        "optional": true
      },
      {
        "command": "COMMANDS",
        "name": ["which"],
        "type": ["string"],
        "optional": true
      },
      {
        "name": "param",
        "type": "string",
        "variadic": true
      }
    ],
    "group": "webhook"
  },
  "DELHOOK": {
    "summary": "Removes a webhook",
    "arguments": [
      {
        "name": "name",
        "type": "string"
      }
    ],
    "group": "webhook"
  },
  "HOOKS": {
    "summary": "Finds all hooks matching a pattern",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "group": "webhook"
  },
  "PDELHOOK": {
    "summary": "Removes all hooks matching a pattern",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "group": "webhook"
  },

  "SETCHAN": {
    "summary": "Creates a pubsub channel which points to geofenced search",
    "arguments": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "command": "META",
        "name": ["name", "value"],
        "type": ["string", "string"],
        "optional": true,
        "multiple": true
      },
      {
        "command": "EX",
        "name": ["seconds"],
        "type": ["double"],
        "optional": true,
        "multiple": false
      },
      {
        "enum": ["NEARBY", "WITHIN", "INTERSECTS"]
      },
      {
        "name": "key",
        "type": "string"
      },
      {
        "command": "FENCE",
        "name": [],
        "type": []
      },
      {
        "command": "DETECT",
        "name": ["what"],
        "type": ["string"],
        "optional": true
      },
      {
        "command": "COMMANDS",
        "name": ["which"],
        "type": ["string"],
        "optional": true
      },
      {
        "name": "param",
        "type": "string",
        "variadic": true
      }
    ],
    "group": "pubsub"
  },
  "DELCHAN": {
    "summary": "Removes a channel",
    "arguments": [
      {
        "name": "name",
        "type": "string"
      }
    ],
    "group": "pubsub"
  },
  "CHANS": {
    "summary": "Finds all channels matching a pattern",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "group": "pubsub"
  },
  "PDELCHAN": {
    "summary": "Removes all channels matching a pattern",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "group": "pubsub"
  },
  "SUBSCRIBE": {
    "summary": "Subscribe to a geofence channel",
    "arguments": [
      {
        "name": "channel",
        "type": "string",
        "variadic": true
      }
    ],
    "group": "pubsub"
  },
  "PSUBSCRIBE": {
    "summary": "Subscribes the client to the given patterns",
    "arguments": [
      {
        "name": "pattern",
        "type": "pattern",
        "variadic": true
      }
    ],
    "group": "pubsub"
  },
  "PDEL": {
    "summary": "Removes all objects matching a pattern",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "pattern",
        "type": "pattern"
      }
    ],
    "group": "keys"
  },
  "JGET": {
    "summary": "Get a value from a JSON document",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "path",
        "type": "string"
      },
      {
        "command": "RAW",
        "name": [],
        "type": [],
        "optional": true
      }
    ],
    "group": "keys"
  },
  "JSET": {
    "summary": "Set a value in a JSON document",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "path",
        "type": "string"
      },
      {
        "name": "value",
        "type": "string"
      },
      {
        "name": [],
        "optional": true,
        "enumargs": [
          {
            "name": "RAW"
          },
          {
            "name": "STR"
          }
        ]
      }
    ],
    "group": "keys"
  },
  "JDEL": {
    "summary": "Delete a value from a JSON document",
    "complexity": "O(1)",
    "arguments": [
      {
        "name": "key",
        "type": "string"
      },
      {
        "name": "id",
        "type": "string"
      },
      {
        "name": "path",
        "type": "string"
      }
    ],
    "group": "keys"
  },
  "EVAL": {
    "summary": "Evaluates a Lua script",
    "complexity": "Depends on the evaluated script",
    "arguments": [
      {
        "name": "script",
        "type": "string"
      },
      {
        "name": "numkeys",
        "type": "integer"
      },
      {
        "name": "key",
        "type": "string",
        "optional": true,
        "multiple": true
      },
      {
        "name": "arg",
        "type": "string",
        "optional": true,
        "multiple": true
      }
    ],
    "since": "1.10.0",
    "group": "scripting"
  },
  "EVALSHA": {
    "summary": "Evaluates a Lua script cached on the server by its SHA1 digest",
    "complexity": "Depends on the evaluated script",
    "arguments": [
      {
        "name": "sha1",
        "type": "string"
      },
      {
        "name": "numkeys",
        "type": "integer"
      },
      {
        "name": "key",
        "type": "string",
        "optional": true,
        "multiple": true
      },
      {
        "name": "arg",
        "type": "string",
        "optional": true,
        "multiple": true
      }
    ],
    "since": "1.10.0",
    "group": "scripting"
  },
  "EVALRO": {
    "summary": "Evaluates a read-only Lua script",
    "complexity": "Depends on the evaluated script",
    "arguments": [
      {
        "name": "script",
        "type": "string"
      },
      {
        "name": "numkeys",
        "type": "integer"
      },
      {
        "name": "key",
        "type": "string",
        "optional": true,
        "multiple": true
      },
      {
        "name": "arg",
        "type": "string",
        "optional": true,
        "multiple": true
      }
    ],
    "since": "1.10.0",
    "group": "scripting"
  },
  "EVALROSHA": {
    "summary": "Evaluates a read-only Lua script cached on the server by its SHA1 di
Download .txt
gitextract_ljil7_jn/

├── .github/
│   ├── CONTRIBUTING.md
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd/
│   ├── tile38-benchmark/
│   │   ├── az/
│   │   │   └── az.go
│   │   └── main.go
│   ├── tile38-cli/
│   │   └── main.go
│   ├── tile38-luamemtest/
│   │   └── main.go
│   └── tile38-server/
│       └── main.go
├── core/
│   ├── commands.go
│   ├── commands.json
│   ├── commands_gen.go
│   ├── commands_test.go
│   ├── gen.sh
│   └── version.go
├── go.mod
├── go.sum
├── internal/
│   ├── bing/
│   │   ├── bing.go
│   │   ├── bing_test.go
│   │   ├── ext.go
│   │   └── ext_test.go
│   ├── buffer/
│   │   ├── buffer.go
│   │   └── buffer_test.go
│   ├── clip/
│   │   ├── clip.go
│   │   ├── clip_test.go
│   │   ├── collection.go
│   │   ├── feature.go
│   │   ├── linestring.go
│   │   ├── point.go
│   │   ├── polygon.go
│   │   └── rect.go
│   ├── collection/
│   │   ├── collection.go
│   │   ├── collection_test.go
│   │   ├── geodesic.go
│   │   └── string.go
│   ├── deadline/
│   │   └── deadline.go
│   ├── endpoint/
│   │   ├── amqp.go
│   │   ├── cfqueue.go
│   │   ├── disque.go
│   │   ├── endpoint.go
│   │   ├── eventHub.go
│   │   ├── grpc.go
│   │   ├── http.go
│   │   ├── kafka.go
│   │   ├── local.go
│   │   ├── mqtt.go
│   │   ├── nats.go
│   │   ├── pubsub.go
│   │   ├── redis.go
│   │   ├── scram_client.go
│   │   └── sqs.go
│   ├── field/
│   │   ├── field.go
│   │   ├── field_test.go
│   │   ├── list_binary.go
│   │   ├── list_struct.go
│   │   └── list_test.go
│   ├── glob/
│   │   ├── glob.go
│   │   ├── glob_test.go
│   │   └── match.go
│   ├── hservice/
│   │   ├── gen.sh
│   │   ├── hservice.pb.go
│   │   └── hservice.proto
│   ├── log/
│   │   ├── log.go
│   │   └── log_test.go
│   ├── object/
│   │   ├── object_binary.go
│   │   ├── object_struct.go
│   │   └── object_test.go
│   ├── server/
│   │   ├── aof.go
│   │   ├── aofmigrate.go
│   │   ├── aofshrink.go
│   │   ├── bson.go
│   │   ├── bson_test.go
│   │   ├── checksum.go
│   │   ├── client.go
│   │   ├── config.go
│   │   ├── crud.go
│   │   ├── dev.go
│   │   ├── expire.go
│   │   ├── expr.go
│   │   ├── expression.go
│   │   ├── fence.go
│   │   ├── follow.go
│   │   ├── group.go
│   │   ├── hooks.go
│   │   ├── json.go
│   │   ├── json_test.go
│   │   ├── keys.go
│   │   ├── live.go
│   │   ├── metrics.go
│   │   ├── monitor.go
│   │   ├── must.go
│   │   ├── must_test.go
│   │   ├── mvt.go
│   │   ├── mvt_test.go
│   │   ├── output.go
│   │   ├── pubqueue.go
│   │   ├── pubsub.go
│   │   ├── readonly.go
│   │   ├── respconn.go
│   │   ├── scan.go
│   │   ├── scanner.go
│   │   ├── scanner_test.go
│   │   ├── scripts.go
│   │   ├── search.go
│   │   ├── server.go
│   │   ├── stats.go
│   │   ├── stats_cpu.go
│   │   ├── stats_cpu_darlin.go
│   │   ├── test.go
│   │   ├── token.go
│   │   └── token_test.go
│   ├── sstring/
│   │   ├── sstring.go
│   │   └── sstring_test.go
│   └── viewer/
│       ├── index.html
│       └── viewer.go
├── scripts/
│   ├── RELEASE.md
│   ├── build.sh
│   ├── docker-push.sh
│   ├── package.sh
│   └── test.sh
└── tests/
    ├── 107/
    │   ├── .gitignore
    │   ├── LINK
    │   └── main.go
    ├── 616/
    │   └── main.go
    ├── README.md
    ├── aof_legacy
    ├── aof_test.go
    ├── client_test.go
    ├── fence_roaming_test.go
    ├── fence_test.go
    ├── follower_test.go
    ├── json_test.go
    ├── keys_search_test.go
    ├── keys_test.go
    ├── metrics_test.go
    ├── mock_io_test.go
    ├── mock_test.go
    ├── monitor_test.go
    ├── proto_test.go
    ├── scripts_test.go
    ├── stats_test.go
    ├── testcmd_test.go
    ├── tests_test.go
    └── timeout_test.go
Download .txt
SYMBOL INDEX (1191 symbols across 122 files)

FILE: cmd/tile38-benchmark/main.go
  function showHelp (line 39) | func showHelp() bool {
  function parseArgs (line 65) | func parseArgs() bool {
  function fillOpts (line 143) | func fillOpts() *redbench.Options {
  function randPoint (line 155) | func randPoint() (lat, lon float64) {
  function isValidRect (line 159) | func isValidRect(minlat, minlon, maxlat, maxlon float64) bool {
  function randRect (line 163) | func randRect(meters float64) (minlat, minlon, maxlat, maxlon float64) {
  function prepFn (line 176) | func prepFn(conn net.Conn) bool {
  function main (line 205) | func main() {
  constant earthRadius (line 737) | earthRadius = 6371e3
  function toRadians (line 739) | func toRadians(deg float64) float64 { return deg * math.Pi / 180 }
  function toDegrees (line 740) | func toDegrees(rad float64) float64 { return rad * 180 / math.Pi }
  function destinationPoint (line 743) | func destinationPoint(lat, lon, meters, bearingDegrees float64) (destLat...

FILE: cmd/tile38-cli/main.go
  function getEnv (line 25) | func getEnv(name string, defaultValue string) string {
  function userHomeDir (line 33) | func userHomeDir() string {
  type connError (line 48) | type connError struct
  function showHelp (line 64) | func showHelp() bool {
  function parseArgs (line 85) | func parseArgs() bool {
  function refusedErrorString (line 171) | func refusedErrorString(addr string) string {
  function jsonOK (line 177) | func jsonOK(msg []byte) bool {
  function main (line 181) | func main() {
  function convert2termresp (line 451) | func convert2termresp(msg []byte) []byte {
  function convert2termjson (line 464) | func convert2termjson(msg []byte) []byte {
  function convert2termrespval (line 471) | func convert2termrespval(v resp.Value, spaces int) string {
  function numlen (line 502) | func numlen(n int) int {
  function help (line 518) | func help(arg string) error {
  constant liveJSON (line 566) | liveJSON = `{"ok":true,"live":true}`
  type client (line 568) | type client struct
    method Do (line 581) | func (c *client) Do(command string) ([]byte, error) {
    method readResp (line 589) | func (c *client) readResp() ([]byte, error) {
    method readArray (line 606) | func (c *client) readArray() ([]byte, error) {
    method readBulk (line 625) | func (c *client) readBulk() ([]byte, error) {
    method readLine (line 648) | func (c *client) readLine() ([]byte, error) {
    method Reader (line 663) | func (c *client) Reader() io.Reader {
    method readLiveResp (line 667) | func (c *client) readLiveResp() (message []byte, err error) {
  function clientDial (line 573) | func clientDial(network, addr string) (*client, error) {
  function plainToCompat (line 673) | func plainToCompat(message string) []byte {
  function clearScreen (line 719) | func clearScreen() {

FILE: cmd/tile38-luamemtest/main.go
  function Sha1Sum (line 18) | func Sha1Sum(s string) string {
  function ConvertToResp (line 25) | func ConvertToResp(val lua.LValue) resp.Value {
  function ConvertToLua (line 78) | func ConvertToLua(L *lua.LState, val resp.Value) lua.LValue {
  function luaTile38Call (line 105) | func luaTile38Call(evalcmd string, cmd string, args ...string) (resp.Val...
  function NewLuaState (line 117) | func NewLuaState() *lua.LState {
  function makeSafeErr (line 187) | func makeSafeErr(err error) error {
  function runLuaFunc (line 191) | func runLuaFunc(luaState *lua.LState, script string, name string) resp.V...
  function runMany (line 207) | func runMany(luaState *lua.LState, start int, num int) int {
  function printMemStats (line 221) | func printMemStats() {
  function testLua (line 236) | func testLua() {
  function main (line 279) | func main() {

FILE: cmd/tile38-server/main.go
  type hserver (line 55) | type hserver struct
    method Send (line 57) | func (s *hserver) Send(ctx context.Context, in *hservice.MessageReques...
  function main (line 61) | func main() {

FILE: core/commands.go
  constant clear (line 11) | clear  = "\x1b[0m"
  constant bright (line 12) | bright = "\x1b[1m"
  constant gray (line 13) | gray   = "\x1b[90m"
  constant yellow (line 14) | yellow = "\x1b[33m"
  type Command (line 18) | type Command struct
    method String (line 29) | func (c Command) String() string {
    method TermOutput (line 38) | func (c Command) TermOutput(indent string) string {
  type EnumArg (line 52) | type EnumArg struct
    method String (line 58) | func (a EnumArg) String() string {
  type Argument (line 67) | type Argument struct
    method String (line 79) | func (a Argument) String() string {
    method NameTypes (line 141) | func (a Argument) NameTypes() (names, types []string) {
  function parseAnyStringArray (line 125) | func parseAnyStringArray(any interface{}) []string {

FILE: core/commands_gen.go
  constant clear (line 11) | clear  = "\x1b[0m"
  constant bright (line 12) | bright = "\x1b[1m"
  constant gray (line 13) | gray   = "\x1b[90m"
  constant yellow (line 14) | yellow = "\x1b[33m"
  type Command (line 18) | type Command struct
    method String (line 29) | func (c Command) String() string {
    method TermOutput (line 38) | func (c Command) TermOutput(indent string) string {
  type EnumArg (line 52) | type EnumArg struct
    method String (line 58) | func (a EnumArg) String() string {
  type Argument (line 67) | type Argument struct
    method String (line 79) | func (a Argument) String() string {
    method NameTypes (line 141) | func (a Argument) NameTypes() (names, types []string) {
  function parseAnyStringArray (line 125) | func parseAnyStringArray(any interface{}) []string {

FILE: core/commands_test.go
  function TestCommands (line 9) | func TestCommands(t *testing.T) {

FILE: internal/bing/bing.go
  constant EarthRadius (line 9) | EarthRadius = 6378137.0
  constant MinLatitude (line 11) | MinLatitude = -85.05112878
  constant MaxLatitude (line 13) | MaxLatitude = 85.05112878
  constant MinLongitude (line 15) | MinLongitude = -180.0
  constant MaxLongitude (line 17) | MaxLongitude = 180.0
  constant TileSize (line 19) | TileSize = 256
  constant MaxLevelOfDetail (line 21) | MaxLevelOfDetail = 38
  function clip (line 29) | func clip(n, minValue, maxValue float64) float64 {
  function MapSize (line 42) | func MapSize(levelOfDetail uint64) uint64 {
  function LatLongToPixelXY (line 70) | func LatLongToPixelXY(latitude, longitude float64, levelOfDetail uint64)...
  function PixelXYToLatLong (line 88) | func PixelXYToLatLong(pixelX, pixelY int64, levelOfDetail uint64) (latit...
  function PixelXYToTileXY (line 102) | func PixelXYToTileXY(pixelX, pixelY int64) (tileX, tileY int64) {
  function TileXYToPixelXY (line 111) | func TileXYToPixelXY(tileX, tileY int64) (pixelX, pixelY int64) {
  function TileXYToQuadKey (line 120) | func TileXYToQuadKey(tileX, tileY int64, levelOfDetail uint64) string {
  function QuadKeyToTileXY (line 144) | func QuadKeyToTileXY(quadKey string) (tileX, tileY int64, levelOfDetail ...

FILE: internal/bing/bing_test.go
  function TestLevelFuzz (line 9) | func TestLevelFuzz(t *testing.T) {
  function TestInvalidQuadKeyFuzz (line 44) | func TestInvalidQuadKeyFuzz(t *testing.T) {
  function TestLatLonClippingFuzz (line 76) | func TestLatLonClippingFuzz(t *testing.T) {
  function TestIssue302 (line 96) | func TestIssue302(t *testing.T) {

FILE: internal/bing/ext.go
  function LatLongToQuad (line 6) | func LatLongToQuad(latitude, longitude float64, levelOfDetail uint64, it...
  function partForTileXY (line 16) | func partForTileXY(tileX, tileY int64, levelOfDetail uint64) int {
  function TileXYToBounds (line 30) | func TileXYToBounds(tileX, tileY int64, levelOfDetail uint64) (minLat, m...
  function QuadKeyToBounds (line 52) | func QuadKeyToBounds(quadkey string) (minLat, minLon, maxLat, maxLon flo...

FILE: internal/bing/ext_test.go
  function TestIteratorFuzz (line 9) | func TestIteratorFuzz(t *testing.T) {
  function TestExt (line 35) | func TestExt(t *testing.T) {

FILE: internal/buffer/buffer.go
  constant bufferSteps (line 16) | bufferSteps = 15
  function Simple (line 19) | func Simple(g geojson.Object, meters float64) (geojson.Object, error) {
  function bufferSimplePoint (line 59) | func bufferSimplePoint(p geometry.Point, meters float64) *geojson.Polygon {
  function bufferSimpleGeometries (line 90) | func bufferSimpleGeometries(objs []geojson.Object, meters float64,
  function bufferSimpleFeatures (line 103) | func bufferSimpleFeatures(objs []geojson.Object, meters float64,
  function appendBufferSimpleSeries (line 117) | func appendBufferSimpleSeries(dst []geojson.Object, s geometry.Series, m...
  function appendSimpleBufferSegment (line 126) | func appendSimpleBufferSegment(dst []geojson.Object, seg geometry.Segment,
  function bufferSimplePolygon (line 153) | func bufferSimplePolygon(p *geojson.Polygon, meters float64,
  function bufferSimpleLineString (line 165) | func bufferSimpleLineString(l *geojson.LineString, meters float64,

FILE: internal/buffer/buffer_test.go
  constant lineString (line 10) | lineString = `{"type":"LineString","coordinates":[
  function TestBufferLineString (line 30) | func TestBufferLineString(t *testing.T) {
  constant polygon (line 47) | polygon = `{"type": "Polygon","coordinates":[
  function TestBufferPolygon (line 92) | func TestBufferPolygon(t *testing.T) {

FILE: internal/clip/clip.go
  function Clip (line 9) | func Clip(
  function clipSegment (line 31) | func clipSegment(seg geometry.Segment, rect geometry.Rect) (
  function clipRing (line 57) | func clipRing(ring []geometry.Point, bbox geometry.Rect) (
  function getCode (line 99) | func getCode(bbox geometry.Rect, point geometry.Point) (code uint8) {
  function intersect (line 117) | func intersect(bbox geometry.Rect, code uint8, start, end geometry.Point) (

FILE: internal/clip/clip_test.go
  function LO (line 10) | func LO(points []geometry.Point) *geojson.LineString {
  function RO (line 14) | func RO(minX, minY, maxX, maxY float64) *geojson.Rect {
  function PPO (line 21) | func PPO(exterior []geometry.Point, holes [][]geometry.Point) *geojson.P...
  function TestClipLineStringSimple (line 25) | func TestClipLineStringSimple(t *testing.T) {
  function TestClipPolygonSimple (line 40) | func TestClipPolygonSimple(t *testing.T) {
  function TestClipPolygon2 (line 72) | func TestClipPolygon2(t *testing.T) {

FILE: internal/clip/collection.go
  function clipCollection (line 8) | func clipCollection(

FILE: internal/clip/feature.go
  function clipFeature (line 8) | func clipFeature(

FILE: internal/clip/linestring.go
  function clipLineString (line 8) | func clipLineString(

FILE: internal/clip/point.go
  function clipPoint (line 8) | func clipPoint(

FILE: internal/clip/polygon.go
  function clipPolygon (line 8) | func clipPolygon(

FILE: internal/clip/rect.go
  function clipRect (line 8) | func clipRect(

FILE: internal/collection/collection.go
  constant yieldStep (line 17) | yieldStep = 256
  type Cursor (line 20) | type Cursor interface
  function byID (line 25) | func byID(a, b *object.Object) bool {
  function byValue (line 29) | func byValue(a, b *object.Object) bool {
  function byExpires (line 42) | func byExpires(a, b *object.Object) bool {
  type Collection (line 54) | type Collection struct
    method Count (line 77) | func (c *Collection) Count() int {
    method StringCount (line 82) | func (c *Collection) StringCount() int {
    method PointCount (line 87) | func (c *Collection) PointCount() int {
    method TotalWeight (line 92) | func (c *Collection) TotalWeight() int {
    method Bounds (line 97) | func (c *Collection) Bounds() (minX, minY, maxX, maxY float64) {
    method indexDelete (line 109) | func (c *Collection) indexDelete(item *object.Object) {
    method indexInsert (line 115) | func (c *Collection) indexInsert(item *object.Object) {
    method Set (line 164) | func (c *Collection) Set(obj *object.Object) (prev *object.Object) {
    method setFill (line 170) | func (c *Collection) setFill(prev, obj *object.Object) {
    method Delete (line 201) | func (c *Collection) Delete(id string) (prev *object.Object) {
    method Get (line 225) | func (c *Collection) Get(id string) *object.Object {
    method Scan (line 231) | func (c *Collection) Scan(
    method ScanRange (line 262) | func (c *Collection) ScanRange(
    method SearchValues (line 304) | func (c *Collection) SearchValues(
    method SearchValuesRange (line 335) | func (c *Collection) SearchValuesRange(start, end string, desc bool,
    method ScanGreaterOrEqual (line 376) | func (c *Collection) ScanGreaterOrEqual(id string, desc bool,
    method geoSearch (line 405) | func (c *Collection) geoSearch(
    method geoSparse (line 429) | func (c *Collection) geoSparse(
    method geoSparseInner (line 447) | func (c *Collection) geoSparseInner(
    method Within (line 493) | func (c *Collection) Within(
    method Intersects (line 534) | func (c *Collection) Intersects(
    method Nearby (line 575) | func (c *Collection) Nearby(
    method ScanExpires (line 622) | func (c *Collection) ScanExpires(iter func(o *object.Object) bool) {
  function New (line 68) | func New() *Collection {
  constant dRNDTOWARDS (line 121) | dRNDTOWARDS = (1.0 - 1.0/8388608.0)
  constant dRNDAWAY (line 122) | dRNDAWAY = (1.0 + 1.0/8388608.0)
  function rtreeValueDown (line 124) | func rtreeValueDown(d float64) float32 {
  function rtreeValueUp (line 135) | func rtreeValueUp(d float64) float32 {
  function rtreeItem (line 147) | func rtreeItem(item *object.Object) (min, max [2]float32, data *object.O...
  function rtreeRect (line 152) | func rtreeRect(rect geometry.Rect) (min, max [2]float32) {
  function bLT (line 372) | func bLT(tr *btree.BTreeG[*object.Object], a, b *object.Object) bool { r...
  function bGT (line 373) | func bGT(tr *btree.BTreeG[*object.Object], a, b *object.Object) bool { r...
  function nextStep (line 611) | func nextStep(step uint64, cursor Cursor, deadline *deadline.Deadline) {

FILE: internal/collection/collection_test.go
  function PO (line 18) | func PO(x, y float64) *geojson.Point {
  function init (line 22) | func init() {
  function expect (line 28) | func expect(t testing.TB, expect bool) {
  function bounds (line 35) | func bounds(c *Collection) geometry.Rect {
  function TestCollectionNewCollection (line 43) | func TestCollectionNewCollection(t *testing.T) {
  function toFields (line 72) | func toFields(fNames, fValues []string) field.List {
  function TestCollectionSet (line 80) | func TestCollectionSet(t *testing.T) {
  function fieldValueAt (line 178) | func fieldValueAt(fields field.List, index int) string {
  function TestCollectionScan (line 194) | func TestCollectionScan(t *testing.T) {
  function makeFields (line 281) | func makeFields(entries ...field.Field) field.List {
  function TestCollectionSearch (line 289) | func TestCollectionSearch(t *testing.T) {
  function TestCollectionWeight (line 352) | func TestCollectionWeight(t *testing.T) {
  function TestSpatialSearch (line 390) | func TestSpatialSearch(t *testing.T) {
  function TestCollectionSparse (line 497) | func TestCollectionSparse(t *testing.T) {
  function testCollectionVerifyContents (line 556) | func testCollectionVerifyContents(t *testing.T, c *Collection, objs map[...
  function TestManyCollections (line 570) | func TestManyCollections(t *testing.T) {
  type testPointItem (line 606) | type testPointItem struct
  function makeBenchFields (line 612) | func makeBenchFields(nFields int) field.List {
  function BenchmarkInsert_Fields (line 622) | func BenchmarkInsert_Fields(t *testing.B) {
  function BenchmarkInsert_NoFields (line 626) | func BenchmarkInsert_NoFields(t *testing.B) {
  function benchmarkInsert (line 630) | func benchmarkInsert(t *testing.B, nFields int) {
  function BenchmarkReplace_Fields (line 647) | func BenchmarkReplace_Fields(t *testing.B) {
  function BenchmarkReplace_NoFields (line 651) | func BenchmarkReplace_NoFields(t *testing.B) {
  function benchmarkReplace (line 655) | func benchmarkReplace(t *testing.B, nFields int) {
  function BenchmarkGet_Fields (line 678) | func BenchmarkGet_Fields(t *testing.B) {
  function BenchmarkGet_NoFields (line 682) | func BenchmarkGet_NoFields(t *testing.B) {
  function benchmarkGet (line 686) | func benchmarkGet(t *testing.B, nFields int) {
  function BenchmarkRemove_Fields (line 709) | func BenchmarkRemove_Fields(t *testing.B) {
  function BenchmarkRemove_NoFields (line 713) | func BenchmarkRemove_NoFields(t *testing.B) {
  function benchmarkRemove (line 717) | func benchmarkRemove(t *testing.B, nFields int) {
  function BenchmarkScan_Fields (line 740) | func BenchmarkScan_Fields(t *testing.B) {
  function BenchmarkScan_NoFields (line 744) | func BenchmarkScan_NoFields(t *testing.B) {
  function benchmarkScan (line 748) | func benchmarkScan(t *testing.B, nFields int) {

FILE: internal/collection/geodesic.go
  function geodeticDistAlgo (line 9) | func geodeticDistAlgo(center [2]float64) (
  function pointRectDistGeodeticDeg (line 29) | func pointRectDistGeodeticDeg(pLat, pLng, minLat, minLng, maxLat, maxLng...
  function pointRectDistGeodeticRad (line 38) | func pointRectDistGeodeticRad(φq, λq, φl, λl, φh, λh float64) float64 {

FILE: internal/collection/string.go
  type String (line 10) | type String
    method Spatial (line 14) | func (s String) Spatial() geojson.Spatial {
    method ForEach (line 18) | func (s String) ForEach(iter func(geom geojson.Object) bool) bool {
    method Empty (line 22) | func (s String) Empty() bool {
    method Valid (line 26) | func (s String) Valid() bool {
    method Rect (line 30) | func (s String) Rect() geometry.Rect {
    method Center (line 34) | func (s String) Center() geometry.Point {
    method AppendJSON (line 38) | func (s String) AppendJSON(dst []byte) []byte {
    method String (line 43) | func (s String) String() string {
    method JSON (line 47) | func (s String) JSON() string {
    method MarshalJSON (line 51) | func (s String) MarshalJSON() ([]byte, error) {
    method Within (line 55) | func (s String) Within(obj geojson.Object) bool {
    method Contains (line 59) | func (s String) Contains(obj geojson.Object) bool {
    method Intersects (line 63) | func (s String) Intersects(obj geojson.Object) bool {
    method NumPoints (line 67) | func (s String) NumPoints() int {
    method Distance (line 71) | func (s String) Distance(obj geojson.Object) float64 {
    method Members (line 75) | func (s String) Members() string {

FILE: internal/deadline/deadline.go
  type Deadline (line 6) | type Deadline struct
    method Check (line 19) | func (dl *Deadline) Check() {
    method Hit (line 30) | func (dl *Deadline) Hit() bool {
    method GetDeadlineTime (line 36) | func (dl *Deadline) GetDeadlineTime() time.Time {
  function New (line 12) | func New(dl time.Time) *Deadline {

FILE: internal/endpoint/amqp.go
  constant amqpExpiresAfter (line 12) | amqpExpiresAfter = time.Second * 30
  type AMQPConn (line 15) | type AMQPConn struct
    method Expired (line 25) | func (conn *AMQPConn) Expired() bool {
    method ExpireNow (line 38) | func (conn *AMQPConn) ExpireNow() {
    method close (line 45) | func (conn *AMQPConn) close() {
    method Send (line 54) | func (conn *AMQPConn) Send(msg string) error {
  function newAMQPConn (line 140) | func newAMQPConn(ep Endpoint) *AMQPConn {

FILE: internal/endpoint/cfqueue.go
  constant cfqueueExpiresAfter (line 13) | cfqueueExpiresAfter = time.Second * 30
  type CFQueueConn (line 16) | type CFQueueConn struct
    method Expired (line 25) | func (conn *CFQueueConn) Expired() bool {
    method ExpireNow (line 38) | func (conn *CFQueueConn) ExpireNow() {
    method close (line 45) | func (conn *CFQueueConn) close() {
    method Send (line 52) | func (conn *CFQueueConn) Send(msg string) error {
  function newCFQueueConn (line 87) | func newCFQueueConn(ep Endpoint) *CFQueueConn {

FILE: internal/endpoint/disque.go
  constant disqueExpiresAfter (line 12) | disqueExpiresAfter = time.Second * 30
  type DisqueConn (line 15) | type DisqueConn struct
    method Expired (line 31) | func (conn *DisqueConn) Expired() bool {
    method ExpireNow (line 44) | func (conn *DisqueConn) ExpireNow() {
    method close (line 51) | func (conn *DisqueConn) close() {
    method Send (line 59) | func (conn *DisqueConn) Send(msg string) error {
  function newDisqueConn (line 23) | func newDisqueConn(ep Endpoint) *DisqueConn {

FILE: internal/endpoint/endpoint.go
  type Protocol (line 18) | type Protocol
  constant Local (line 22) | Local = Protocol("local")
  constant HTTP (line 24) | HTTP = Protocol("http")
  constant Disque (line 26) | Disque = Protocol("disque")
  constant GRPC (line 28) | GRPC = Protocol("grpc")
  constant Redis (line 30) | Redis = Protocol("redis")
  constant Kafka (line 32) | Kafka = Protocol("kafka")
  constant MQTT (line 34) | MQTT = Protocol("mqtt")
  constant AMQP (line 36) | AMQP = Protocol("amqp")
  constant SQS (line 38) | SQS = Protocol("sqs")
  constant PubSub (line 40) | PubSub = Protocol("pubsub")
  constant NATS (line 42) | NATS = Protocol("nats")
  constant EventHub (line 44) | EventHub = Protocol("sb")
  constant CFQueue (line 46) | CFQueue = Protocol("cf-queue")
  type Endpoint (line 50) | type Endpoint struct
  type Conn (line 150) | type Conn interface
  type Manager (line 157) | type Manager struct
    method Shutdown (line 176) | func (epc *Manager) Shutdown() {
    method run (line 188) | func (epc *Manager) run() {
    method Validate (line 208) | func (epc *Manager) Validate(url string) error {
    method Send (line 214) | func (epc *Manager) Send(endpoint, msg string) error {
  function NewManager (line 166) | func NewManager(publisher LocalPublisher) *Manager {
  function parseEndpoint (line 271) | func parseEndpoint(s string) (Endpoint, error) {
  function queryInt (line 876) | func queryInt(s string) int {
  function queryBool (line 881) | func queryBool(s string) bool {

FILE: internal/endpoint/eventHub.go
  type EvenHubConn (line 16) | type EvenHubConn struct
    method Expired (line 27) | func (conn *EvenHubConn) Expired() bool {
    method ExpireNow (line 32) | func (conn *EvenHubConn) ExpireNow() {
    method Send (line 36) | func (conn *EvenHubConn) Send(msg string) error {
  function newEventHubConn (line 20) | func newEventHubConn(ep Endpoint) *EvenHubConn {

FILE: internal/endpoint/grpc.go
  constant grpcExpiresAfter (line 14) | grpcExpiresAfter = time.Second * 30
  type GRPCConn (line 17) | type GRPCConn struct
    method Expired (line 34) | func (conn *GRPCConn) Expired() bool {
    method ExpireNow (line 47) | func (conn *GRPCConn) ExpireNow() {
    method close (line 54) | func (conn *GRPCConn) close() {
    method Send (line 62) | func (conn *GRPCConn) Send(msg string) error {
  function newGRPCConn (line 26) | func newGRPCConn(ep Endpoint) *GRPCConn {

FILE: internal/endpoint/http.go
  constant httpExpiresAfter (line 12) | httpExpiresAfter       = time.Second * 30
  constant httpRequestTimeout (line 13) | httpRequestTimeout     = time.Second * 5
  constant httpMaxIdleConnections (line 14) | httpMaxIdleConnections = 20
  type HTTPConn (line 18) | type HTTPConn struct
    method Expired (line 37) | func (conn *HTTPConn) Expired() bool {
    method ExpireNow (line 42) | func (conn *HTTPConn) ExpireNow() {
    method Send (line 46) | func (conn *HTTPConn) Send(msg string) error {
  function newHTTPConn (line 23) | func newHTTPConn(ep Endpoint) *HTTPConn {

FILE: internal/endpoint/kafka.go
  constant kafkaExpiresAfter (line 19) | kafkaExpiresAfter = time.Second * 30
  type KafkaConn (line 22) | type KafkaConn struct
    method Expired (line 32) | func (conn *KafkaConn) Expired() bool {
    method ExpireNow (line 45) | func (conn *KafkaConn) ExpireNow() {
    method close (line 52) | func (conn *KafkaConn) close() {
    method Send (line 62) | func (conn *KafkaConn) Send(msg string) error {
  function newKafkaConn (line 200) | func newKafkaConn(ep Endpoint) *KafkaConn {
  function loadClientTLSCert (line 207) | func loadClientTLSCert(KeyFile, CertFile string) ([]tls.Certificate, err...
  function loadRootTLSCert (line 218) | func loadRootTLSCert(CACertFile string) (x509.CertPool, error) {

FILE: internal/endpoint/local.go
  type LocalPublisher (line 4) | type LocalPublisher interface
  type LocalConn (line 9) | type LocalConn struct
    method Expired (line 22) | func (conn *LocalConn) Expired() bool {
    method ExpireNow (line 27) | func (conn *LocalConn) ExpireNow() {
    method Send (line 31) | func (conn *LocalConn) Send(msg string) error {
  function newLocalConn (line 14) | func newLocalConn(ep Endpoint, publisher LocalPublisher) *LocalConn {

FILE: internal/endpoint/mqtt.go
  constant mqttExpiresAfter (line 17) | mqttExpiresAfter   = time.Second * 30
  constant mqttPublishTimeout (line 18) | mqttPublishTimeout = time.Second * 5
  type MQTTConn (line 22) | type MQTTConn struct
    method Expired (line 31) | func (conn *MQTTConn) Expired() bool {
    method ExpireNow (line 44) | func (conn *MQTTConn) ExpireNow() {
    method close (line 51) | func (conn *MQTTConn) close() {
    method Send (line 61) | func (conn *MQTTConn) Send(msg string) error {
  function newMQTTConn (line 126) | func newMQTTConn(ep Endpoint) *MQTTConn {

FILE: internal/endpoint/nats.go
  constant natsExpiresAfter (line 13) | natsExpiresAfter = time.Second * 30
  type NATSConn (line 16) | type NATSConn struct
    method Expired (line 33) | func (conn *NATSConn) Expired() bool {
    method ExpireNow (line 46) | func (conn *NATSConn) ExpireNow() {
    method close (line 53) | func (conn *NATSConn) close() {
    method Send (line 61) | func (conn *NATSConn) Send(msg string) error {
    method publish (line 116) | func (conn *NATSConn) publish(msg string) error {
    method publishJS (line 127) | func (conn *NATSConn) publishJS(msg string) error {
  function newNATSConn (line 25) | func newNATSConn(ep Endpoint) *NATSConn {

FILE: internal/endpoint/pubsub.go
  constant pubsubExpiresAfter (line 13) | pubsubExpiresAfter = time.Second * 30
  type PubSubConn (line 16) | type PubSubConn struct
    method close (line 25) | func (conn *PubSubConn) close() {
    method Send (line 33) | func (conn *PubSubConn) Send(msg string) error {
    method Expired (line 81) | func (conn *PubSubConn) Expired() bool {
    method ExpireNow (line 94) | func (conn *PubSubConn) ExpireNow() {
  function newPubSubConn (line 101) | func newPubSubConn(ep Endpoint) *PubSubConn {

FILE: internal/endpoint/redis.go
  constant redisExpiresAfter (line 11) | redisExpiresAfter = time.Second * 30
  type RedisConn (line 14) | type RedisConn struct
    method Expired (line 30) | func (conn *RedisConn) Expired() bool {
    method ExpireNow (line 43) | func (conn *RedisConn) ExpireNow() {
    method close (line 50) | func (conn *RedisConn) close() {
    method Send (line 58) | func (conn *RedisConn) Send(msg string) error {
  function newRedisConn (line 22) | func newRedisConn(ep Endpoint) *RedisConn {

FILE: internal/endpoint/scram_client.go
  type XDGSCRAMClient (line 15) | type XDGSCRAMClient struct
    method Begin (line 21) | func (x *XDGSCRAMClient) Begin(userName, password, authzID string) (er...
    method Step (line 30) | func (x *XDGSCRAMClient) Step(challenge string) (response string, err ...
    method Done (line 35) | func (x *XDGSCRAMClient) Done() bool {

FILE: internal/endpoint/sqs.go
  constant sqsExpiresAfter (line 18) | sqsExpiresAfter = time.Second * 30
  type SQSConn (line 21) | type SQSConn struct
    method generateSQSURL (line 30) | func (conn *SQSConn) generateSQSURL() string {
    method Expired (line 39) | func (conn *SQSConn) Expired() bool {
    method ExpireNow (line 52) | func (conn *SQSConn) ExpireNow() {
    method close (line 59) | func (conn *SQSConn) close() {
    method Send (line 67) | func (conn *SQSConn) Send(msg string) error {
  function newSQSConn (line 133) | func newSQSConn(ep Endpoint) *SQSConn {
  function probeSQS (line 140) | func probeSQS(s string) bool {
  function sqsRegionFromPlainURL (line 146) | func sqsRegionFromPlainURL(s string) string {
  function isFifoQueue (line 157) | func isFifoQueue(s string) bool {

FILE: internal/field/field.go
  type Kind (line 15) | type Kind
  constant Null (line 18) | Null   = Kind(gjson.Null)
  constant False (line 19) | False  = Kind(gjson.False)
  constant Number (line 20) | Number = Kind(gjson.Number)
  constant String (line 21) | String = Kind(gjson.String)
  constant True (line 22) | True   = Kind(gjson.True)
  constant JSON (line 23) | JSON   = Kind(gjson.JSON)
  type Value (line 26) | type Value struct
    method IsZero (line 32) | func (v Value) IsZero() bool {
    method Equals (line 36) | func (v Value) Equals(b Value) bool {
    method Kind (line 40) | func (v Value) Kind() Kind {
    method Data (line 44) | func (v Value) Data() string {
    method Num (line 48) | func (v Value) Num() float64 {
    method JSON (line 52) | func (v Value) JSON() string {
    method LessCase (line 125) | func (v Value) LessCase(b Value, caseSensitive bool) bool {
    method Less (line 149) | func (v Value) Less(b Value) bool {
  function stringLessInsensitive (line 81) | func stringLessInsensitive(a, b string) bool {
  type Field (line 153) | type Field struct
    method Name (line 158) | func (f Field) Name() string {
    method Value (line 162) | func (f Field) Value() Value {
    method Weight (line 166) | func (f Field) Weight() int {
  function ValueOf (line 174) | func ValueOf(data string) Value {
  function Make (line 231) | func Make(name, data string) Field {

FILE: internal/field/field_test.go
  function mLT (line 9) | func mLT(a, b Value) bool  { return a.Less(b) }
  function mLTE (line 10) | func mLTE(a, b Value) bool { return !mLT(b, a) }
  function mGT (line 11) | func mGT(a, b Value) bool  { return mLT(b, a) }
  function mGTE (line 12) | func mGTE(a, b Value) bool { return !mLT(a, b) }
  function mEQ (line 13) | func mEQ(a, b Value) bool  { return !mLT(a, b) && !mLT(b, a) }
  function TestOrder (line 15) | func TestOrder(t *testing.T) {
  function TestLess (line 41) | func TestLess(t *testing.T) {
  function TestLessCase (line 76) | func TestLessCase(t *testing.T) {
  function TestVarious (line 82) | func TestVarious(t *testing.T) {
  function TestJSON (line 97) | func TestJSON(t *testing.T) {
  function TestField (line 120) | func TestField(t *testing.T) {
  function TestWeight (line 128) | func TestWeight(t *testing.T) {
  function TestNumber (line 132) | func TestNumber(t *testing.T) {

FILE: internal/field/list_binary.go
  constant useSharedNames (line 27) | useSharedNames = true
  type List (line 30) | type List struct
    method Set (line 103) | func (fields List) Set(field Field) List {
    method Get (line 255) | func (fields List) Get(name string) Field {
    method Scan (line 312) | func (fields List) Scan(iter func(field Field) bool) {
    method Len (line 344) | func (fields List) Len() int {
    method Weight (line 370) | func (fields List) Weight() int {
    method String (line 388) | func (fields List) String() string {
  type bytes (line 34) | type bytes struct
  function ptob (line 40) | func ptob(p *byte) []byte {
  function btoa (line 50) | func btoa(b []byte) string {
  function uvarint (line 56) | func uvarint(buf []byte) (int, int) {
  function datakind (line 68) | func datakind(kind Kind) bool {
  function bfield (line 76) | func bfield(name string, kind Kind, data string) Field {
  function delfield (line 155) | func delfield(b []byte, s, e int) *byte {
  function putfield (line 181) | func putfield(b []byte, f Field, s, e int) *byte {
  function MakeList (line 379) | func MakeList(fields []Field) List {

FILE: internal/field/list_struct.go
  type List (line 5) | type List struct
    method bsearch (line 10) | func (fields List) bsearch(name string) (index int, found bool) {
    method Set (line 26) | func (fields List) Set(field Field) List {
    method Get (line 58) | func (fields List) Get(name string) Field {
    method Scan (line 66) | func (fields List) Scan(iter func(field Field) bool) {
    method Len (line 74) | func (fields List) Len() int {
    method Weight (line 78) | func (fields List) Weight() int {

FILE: internal/field/list_test.go
  function TestList (line 13) | func TestList(t *testing.T) {
  function randStr (line 83) | func randStr(n int) string {
  function randVal (line 92) | func randVal(n int) string {
  function TestRandom (line 113) | func TestRandom(t *testing.T) {
  function TestJSONGet (line 183) | func TestJSONGet(t *testing.T) {

FILE: internal/glob/glob.go
  type Glob (line 6) | type Glob struct
  function Match (line 15) | func Match(pattern, str string) (matched bool, err error) {
  function IsGlob (line 20) | func IsGlob(pattern string) bool {
  function Parse (line 32) | func Parse(pattern string, desc bool) *Glob {

FILE: internal/glob/glob_test.go
  function test (line 9) | func test(t *testing.T, pattern string, desc bool, limitsExpect []string...
  function TestGlob (line 25) | func TestGlob(t *testing.T) {
  function testMatch (line 46) | func testMatch(s, pattern string) bool {
  function TestMatch (line 51) | func TestMatch(t *testing.T) {
  function TestWildcardMatch (line 96) | func TestWildcardMatch(t *testing.T) {
  function TestRandomInput (line 398) | func TestRandomInput(t *testing.T) {
  function BenchmarkAscii (line 412) | func BenchmarkAscii(t *testing.B) {
  function BenchmarkUnicode (line 420) | func BenchmarkUnicode(t *testing.B) {

FILE: internal/glob/match.go
  function wildcardMatch (line 39) | func wildcardMatch(pattern, name string) (matched bool, err error) {
  function scanChunk (line 86) | func scanChunk(pattern string) (star bool, chunk, rest string) {
  function matchChunk (line 117) | func matchChunk(chunk, s string) (rest string, ok bool, err error) {
  function getEsc (line 191) | func getEsc(chunk string) (r rune, nchunk string, err error) {

FILE: internal/hservice/hservice.pb.go
  constant _ (line 35) | _ = proto.ProtoPackageIsVersion2
  type MessageRequest (line 38) | type MessageRequest struct
    method Reset (line 42) | func (m *MessageRequest) Reset()                    { *m = MessageRequ...
    method String (line 43) | func (m *MessageRequest) String() string            { return proto.Com...
    method ProtoMessage (line 44) | func (*MessageRequest) ProtoMessage()               {}
    method Descriptor (line 45) | func (*MessageRequest) Descriptor() ([]byte, []int) { return fileDescr...
  type MessageReply (line 48) | type MessageReply struct
    method Reset (line 52) | func (m *MessageReply) Reset()                    { *m = MessageReply{} }
    method String (line 53) | func (m *MessageReply) String() string            { return proto.Compa...
    method ProtoMessage (line 54) | func (*MessageReply) ProtoMessage()               {}
    method Descriptor (line 55) | func (*MessageReply) Descriptor() ([]byte, []int) { return fileDescrip...
  function init (line 57) | func init() {
  constant _ (line 68) | _ = grpc.SupportPackageIsVersion3
  type HookServiceClient (line 72) | type HookServiceClient interface
  type hookServiceClient (line 77) | type hookServiceClient struct
    method Send (line 85) | func (c *hookServiceClient) Send(ctx context.Context, in *MessageReque...
  function NewHookServiceClient (line 81) | func NewHookServiceClient(cc *grpc.ClientConn) HookServiceClient {
  type HookServiceServer (line 96) | type HookServiceServer interface
  function RegisterHookServiceServer (line 101) | func RegisterHookServiceServer(s *grpc.Server, srv HookServiceServer) {
  function _HookService_Send_Handler (line 105) | func _HookService_Send_Handler(srv interface{}, ctx context.Context, dec...
  function init (line 136) | func init() { proto.RegisterFile("hservice.proto", fileDescriptor0) }

FILE: internal/log/log.go
  function init (line 26) | func init() {
  function SetLevel (line 36) | func SetLevel(level int) {
  function Level (line 46) | func Level() int {
  function SetLogJSON (line 50) | func SetLogJSON(logJSON bool) {
  function LogJSON (line 54) | func LogJSON() bool {
  function SetOutput (line 59) | func SetOutput(w io.Writer) {
  function Build (line 68) | func Build(c string) error {
  function Set (line 100) | func Set(sl *zap.SugaredLogger) {
  function Get (line 107) | func Get() *zap.SugaredLogger {
  function Output (line 115) | func Output() io.Writer {
  function log (line 121) | func log(level int, tag, color string, formatted bool, format string, ar...
  function Infof (line 172) | func Infof(format string, args ...interface{}) {
  function Info (line 179) | func Info(args ...interface{}) {
  function HTTPf (line 186) | func HTTPf(format string, args ...interface{}) {
  function HTTP (line 193) | func HTTP(args ...interface{}) {
  function Errorf (line 200) | func Errorf(format string, args ...interface{}) {
  function Error (line 207) | func Error(args ...interface{}) {
  function Warnf (line 214) | func Warnf(format string, args ...interface{}) {
  function Warn (line 221) | func Warn(args ...interface{}) {
  function Debugf (line 228) | func Debugf(format string, args ...interface{}) {
  function Debug (line 235) | func Debug(args ...interface{}) {
  function Printf (line 242) | func Printf(format string, args ...interface{}) {
  function Print (line 247) | func Print(args ...interface{}) {
  function Fatalf (line 252) | func Fatalf(format string, args ...interface{}) {
  function Fatal (line 258) | func Fatal(args ...interface{}) {

FILE: internal/log/log_test.go
  function TestLog (line 14) | func TestLog(t *testing.T) {
  function TestLogJSON (line 24) | func TestLogJSON(t *testing.T) {
  function BenchmarkLogPrintf (line 189) | func BenchmarkLogPrintf(t *testing.B) {
  function BenchmarkLogJSONPrintf (line 199) | func BenchmarkLogJSONPrintf(t *testing.B) {

FILE: internal/object/object_binary.go
  type pointObject (line 12) | type pointObject struct
  type geoObject (line 17) | type geoObject struct
  constant opoint (line 22) | opoint = 1
  constant ogeo (line 23) | ogeo = 2
  type Object (line 25) | type Object struct
    method geo (line 30) | func (o *Object) geo() geojson.Object {
    method ID (line 65) | func (o *Object) ID() string {
    method Fields (line 73) | func (o *Object) Fields() field.List {
    method Expires (line 77) | func (o *Object) Expires() int64 {
    method Rect (line 82) | func (o *Object) Rect() geometry.Rect {
    method Geo (line 90) | func (o *Object) Geo() geojson.Object {
    method String (line 94) | func (o *Object) String() string {
    method IsSpatial (line 102) | func (o *Object) IsSpatial() bool {
    method Weight (line 107) | func (o *Object) Weight() int {
  function uvarint (line 44) | func uvarint(s string) (uint64, int) {
  function varint (line 56) | func varint(s string) (int64, int) {
  function makeHead (line 122) | func makeHead(kind byte, id string, expires int64) string {
  function newPoint (line 136) | func newPoint(id string, pt geometry.Point, expires int64, fields field....
  function newGeo (line 146) | func newGeo(id string, geo geojson.Object, expires int64, fields field.L...
  function New (line 157) | func New(id string, geo geojson.Object, expires int64, fields field.List,

FILE: internal/object/object_struct.go
  type Object (line 11) | type Object struct
    method ID (line 18) | func (o *Object) ID() string {
    method Fields (line 25) | func (o *Object) Fields() field.List {
    method Expires (line 32) | func (o *Object) Expires() int64 {
    method Rect (line 39) | func (o *Object) Rect() geometry.Rect {
    method Geo (line 46) | func (o *Object) Geo() geojson.Object {
    method String (line 53) | func (o *Object) String() string {
    method IsSpatial (line 60) | func (o *Object) IsSpatial() bool {
    method Weight (line 65) | func (o *Object) Weight() int {
  function New (line 80) | func New(id string, geo geojson.Object, expires int64, fields field.List,

FILE: internal/object/object_test.go
  function P (line 12) | func P(x, y float64) geojson.Object {
  function TestObject (line 15) | func TestObject(t *testing.T) {

FILE: internal/server/aof.go
  type errAOFHook (line 23) | type errAOFHook struct
    method Error (line 27) | func (err errAOFHook) Error() string {
  method loadAOF (line 31) | func (s *Server) loadAOF() (err error) {
  function commandErrIsFatal (line 118) | func commandErrIsFatal(err error) bool {
  method flushAOF (line 127) | func (s *Server) flushAOF(sync bool) {
  method writeAOF (line 148) | func (s *Server) writeAOF(args []string, d *commandDetails) error {
  method getQueueCandidates (line 207) | func (s *Server) getQueueCandidates(d *commandDetails) []*Hook {
  method queueHooks (line 276) | func (s *Server) queueHooks(d *commandDetails) error {
  function sortMsgs (line 346) | func sortMsgs(msgs []string) {
  function msgDetectCode (line 363) | func msgDetectCode(detect string) int {
  function stringToUint64 (line 379) | func stringToUint64(s string) uint64 {
  function uint64ToString (line 385) | func uint64ToString(u uint64) string {
  type liveAOFSwitches (line 390) | type liveAOFSwitches struct
    method Error (line 394) | func (s liveAOFSwitches) Error() string {
  method cmdAOFMD5 (line 399) | func (s *Server) cmdAOFMD5(msg *Message) (resp.Value, error) {
  method cmdAOF (line 435) | func (s *Server) cmdAOF(msg *Message) (resp.Value, error) {
  method liveAOF (line 477) | func (s *Server) liveAOF(pos int64, conn net.Conn, rd *PipelineReader, m...

FILE: internal/server/aofmigrate.go
  type LegacyAOFReader (line 19) | type LegacyAOFReader struct
    method ReadCommand (line 29) | func (rd *LegacyAOFReader) ReadCommand() ([]byte, error) {
  function NewLegacyAOFReader (line 81) | func NewLegacyAOFReader(r io.Reader) *LegacyAOFReader {
  method migrateAOF (line 86) | func (s *Server) migrateAOF() error {

FILE: internal/server/aofshrink.go
  constant maxkeys (line 17) | maxkeys = 8
  constant maxids (line 18) | maxids = 32
  constant maxchunk (line 19) | maxchunk = 4 * 1024 * 1024
  method aofshrink (line 21) | func (s *Server) aofshrink() {

FILE: internal/server/bson.go
  function bsonID (line 13) | func bsonID() string {

FILE: internal/server/bson_test.go
  function TestBSON (line 5) | func TestBSON(t *testing.T) {

FILE: internal/server/checksum.go
  method checksum (line 16) | func (s *Server) checksum(pos, size int64) (sum string, err error) {
  function connAOFMD5 (line 57) | func connAOFMD5(conn *RESPConn, pos, size int64) (sum string, err error) {
  method matchChecksums (line 76) | func (s *Server) matchChecksums(conn *RESPConn, pos, size int64) (match ...
  function getEndOfLastValuePositionInFile (line 96) | func getEndOfLastValuePositionInFile(fname string, startPos int64) (int6...
  method followCheckSome (line 140) | func (s *Server) followCheckSome(addr string, followc int, auth string,

FILE: internal/server/client.go
  type Client (line 16) | type Client struct
    method Write (line 41) | func (client *Client) Write(b []byte) (n int, err error) {
  method cmdCLIENT (line 47) | func (s *Server) cmdCLIENT(msg *Message, client *Client) (resp.Value, er...

FILE: internal/server/config.go
  constant defaultKeepAlive (line 17) | defaultKeepAlive     = 300
  constant defaultProtectedMode (line 18) | defaultProtectedMode = "yes"
  constant FollowHost (line 23) | FollowHost      = "follow_host"
  constant FollowPort (line 24) | FollowPort      = "follow_port"
  constant FollowID (line 25) | FollowID        = "follow_id"
  constant FollowPos (line 26) | FollowPos       = "follow_pos"
  constant ReplicaPriority (line 27) | ReplicaPriority = "replica-priority"
  constant ServerID (line 28) | ServerID        = "server_id"
  constant ReadOnly (line 29) | ReadOnly        = "read_only"
  constant RequirePass (line 30) | RequirePass     = "requirepass"
  constant LeaderAuth (line 31) | LeaderAuth      = "leaderauth"
  constant ProtectedMode (line 32) | ProtectedMode   = "protected-mode"
  constant MaxMemory (line 33) | MaxMemory       = "maxmemory"
  constant AutoGC (line 34) | AutoGC          = "autogc"
  constant KeepAlive (line 35) | KeepAlive       = "keepalive"
  constant LogConfig (line 36) | LogConfig       = "logconfig"
  constant AnnounceIP (line 37) | AnnounceIP      = "replica_announce_ip"
  constant AnnouncePort (line 38) | AnnouncePort    = "replica_announce_port"
  type Config (line 44) | type Config struct
    method write (line 152) | func (config *Config) write(writeProperties bool) {
    method setProperty (line 299) | func (config *Config) setProperty(name, value string, fromLoad bool) e...
    method getProperties (line 384) | func (config *Config) getProperties(pattern string) map[string]interfa...
    method getProperty (line 395) | func (config *Config) getProperty(name string) string {
    method followHost (line 491) | func (config *Config) followHost() string {
    method followPort (line 497) | func (config *Config) followPort() int {
    method replicaPriority (line 503) | func (config *Config) replicaPriority() int {
    method serverID (line 509) | func (config *Config) serverID() string {
    method readOnly (line 515) | func (config *Config) readOnly() bool {
    method requirePass (line 521) | func (config *Config) requirePass() string {
    method leaderAuth (line 527) | func (config *Config) leaderAuth() string {
    method protectedMode (line 533) | func (config *Config) protectedMode() string {
    method maxMemory (line 539) | func (config *Config) maxMemory() int {
    method autoGC (line 545) | func (config *Config) autoGC() uint64 {
    method keepAlive (line 551) | func (config *Config) keepAlive() int64 {
    method announceIP (line 557) | func (config *Config) announceIP() string {
    method announcePort (line 563) | func (config *Config) announcePort() int {
    method setFollowHost (line 569) | func (config *Config) setFollowHost(v string) {
    method setFollowPort (line 574) | func (config *Config) setFollowPort(v int) {
    method setReadOnly (line 579) | func (config *Config) setReadOnly(v bool) {
  function loadConfig (line 77) | func loadConfig(path string) (*Config, error) {
  function parseMemSize (line 253) | func parseMemSize(s string) (bytes int64, ok bool) {
  function formatMemSize (line 280) | func formatMemSize(sz int64) string {
  method cmdConfigGet (line 428) | func (s *Server) cmdConfigGet(msg *Message) (res resp.Value, err error) {
  method cmdConfigSet (line 454) | func (s *Server) cmdConfigSet(msg *Message) (res resp.Value, err error) {
  method cmdConfigRewrite (line 480) | func (s *Server) cmdConfigRewrite(msg *Message) (res resp.Value, err err...

FILE: internal/server/crud.go
  method cmdBOUNDS (line 21) | func (s *Server) cmdBOUNDS(msg *Message) (resp.Value, error) {
  method cmdTYPE (line 78) | func (s *Server) cmdTYPE(msg *Message) (resp.Value, error) {
  method cmdGET (line 111) | func (s *Server) cmdGET(msg *Message) (resp.Value, error) {
  function buildObjectResponse (line 176) | func buildObjectResponse(msg *Message, o *object.Object, start time.Time...
  method cmdDEL (line 283) | func (s *Server) cmdDEL(msg *Message) (resp.Value, commandDetails, error) {
  method cmdPDEL (line 351) | func (s *Server) cmdPDEL(msg *Message) (resp.Value, commandDetails, erro...
  method cmdDROPop (line 421) | func (s *Server) cmdDROPop(key string) *collection.Collection {
  method cmdDROP (line 431) | func (s *Server) cmdDROP(msg *Message) (resp.Value, commandDetails, erro...
  method cmdRENAME (line 469) | func (s *Server) cmdRENAME(msg *Message) (resp.Value, commandDetails, er...
  method cmdFLUSHDB (line 547) | func (s *Server) cmdFLUSHDB(msg *Message) (resp.Value, commandDetails, e...
  method cmdSET (line 623) | func (s *Server) cmdSET(msg *Message) (resp.Value, commandDetails, error) {
  function retwerr (line 874) | func retwerr(err error) (resp.Value, commandDetails, error) {
  function retrerr (line 877) | func retrerr(err error) (resp.Value, error) {
  method cmdFSET (line 882) | func (s *Server) cmdFSET(msg *Message) (resp.Value, commandDetails, erro...
  method cmdFGET (line 1016) | func (s *Server) cmdFGET(msg *Message) (resp.Value, error) {
  method cmdEXPIRE (line 1056) | func (s *Server) cmdEXPIRE(msg *Message) (resp.Value, commandDetails, er...
  method cmdPERSIST (line 1120) | func (s *Server) cmdPERSIST(msg *Message) (resp.Value, commandDetails, e...
  method cmdTTL (line 1182) | func (s *Server) cmdTTL(msg *Message) (resp.Value, error) {
  method cmdEXISTS (line 1230) | func (s *Server) cmdEXISTS(msg *Message) (resp.Value, error) {
  method cmdFEXISTS (line 1262) | func (s *Server) cmdFEXISTS(msg *Message) (resp.Value, error) {

FILE: internal/server/dev.go
  function randMassInsertPosition (line 17) | func randMassInsertPosition(minLat, minLon, maxLat, maxLon float64) (flo...
  method cmdMassInsert (line 22) | func (s *Server) cmdMassInsert(msg *Message) (res resp.Value, err error) {
  method cmdSleep (line 151) | func (s *Server) cmdSleep(msg *Message) (res resp.Value, err error) {

FILE: internal/server/expire.go
  constant bgExpireDelay (line 12) | bgExpireDelay = time.Second / 10
  method backgroundExpiring (line 16) | func (s *Server) backgroundExpiring(wg *sync.WaitGroup) {
  method backgroundExpireObjects (line 27) | func (s *Server) backgroundExpireObjects(now time.Time) {
  method backgroundExpireHooks (line 55) | func (s *Server) backgroundExpireHooks(now time.Time) {

FILE: internal/server/expr.go
  type exprPool (line 18) | type exprPool struct
    method Get (line 174) | func (p *exprPool) Get(o *object.Object) *expr.Context {
    method Put (line 181) | func (p *exprPool) Put(ctx *expr.Context) {
  function typeForObject (line 23) | func typeForObject(o *object.Object) expr.Value {
  function resultToValue (line 48) | func resultToValue(r gjson.Result) expr.Value {
  function objExpr (line 68) | func objExpr(o *object.Object, info expr.RefInfo) (expr.Value, error) {
  function newExprPool (line 96) | func newExprPool(s *Server) *exprPool {
  method matchExpr (line 185) | func (where whereT) matchExpr(s *Server, o *object.Object) bool {

FILE: internal/server/expression.go
  type BinaryOp (line 10) | type BinaryOp
  constant NOOP (line 14) | NOOP BinaryOp = iota
  constant AND (line 15) | AND
  constant OR (line 16) | OR
  constant tokenAND (line 17) | tokenAND    = "and"
  constant tokenOR (line 18) | tokenOR     = "or"
  constant tokenNOT (line 19) | tokenNOT    = "not"
  constant tokenLParen (line 20) | tokenLParen = "("
  constant tokenRParen (line 21) | tokenRParen = ")"
  type areaExpression (line 26) | type areaExpression struct
    method String (line 36) | func (e *areaExpression) String() (res string) {
    method maybeNegate (line 62) | func (e *areaExpression) maybeNegate(val bool) bool {
    method testObject (line 70) | func (e *areaExpression) testObject(
    method rawIntersects (line 97) | func (e *areaExpression) rawIntersects(o geojson.Object) bool {
    method rawContains (line 101) | func (e *areaExpression) rawContains(o geojson.Object) bool {
    method rawWithin (line 105) | func (e *areaExpression) rawWithin(o geojson.Object) bool {
    method Intersects (line 109) | func (e *areaExpression) Intersects(o geojson.Object) bool {
    method Contains (line 113) | func (e *areaExpression) Contains(o geojson.Object) bool {
    method Within (line 117) | func (e *areaExpression) Within(o geojson.Object) bool {
    method testExpression (line 122) | func (e *areaExpression) testExpression(
    method rawIntersectsExpr (line 155) | func (e *areaExpression) rawIntersectsExpr(other *areaExpression) bool {
    method rawWithinExpr (line 163) | func (e *areaExpression) rawWithinExpr(other *areaExpression) bool {
    method rawContainsExpr (line 171) | func (e *areaExpression) rawContainsExpr(other *areaExpression) bool {
    method IntersectsExpr (line 179) | func (e *areaExpression) IntersectsExpr(other *areaExpression) bool {
    method WithinExpr (line 183) | func (e *areaExpression) WithinExpr(other *areaExpression) bool {
    method ContainsExpr (line 187) | func (e *areaExpression) ContainsExpr(other *areaExpression) bool {
  type children (line 33) | type children

FILE: internal/server/fence.go
  function FenceMatch (line 19) | func FenceMatch(hookName string, sw *scanWriter, fence *liveFenceSwitche...
  function appendHookDetails (line 32) | func appendHookDetails(b []byte, hookName string, metas []FenceMeta) []b...
  function objIsSpatial (line 52) | func objIsSpatial(obj geojson.Object) bool {
  function hookJSONString (line 57) | func hookJSONString(hookName string, metas []FenceMeta) string {
  function multiGlobMatch (line 61) | func multiGlobMatch(globs []string, s string) bool {
  function fenceMatch (line 74) | func fenceMatch(
  function extendRoamMessage (line 278) | func extendRoamMessage(
  function makemsg (line 337) | func makemsg(
  function fenceMatchObject (line 353) | func fenceMatchObject(fence *liveFenceSwitches, o *object.Object) bool {
  function fenceMatchNearbys (line 373) | func fenceMatchNearbys(
  function fenceMatchRoam (line 421) | func fenceMatchRoam(
  function sortRoamMatches (line 460) | func sortRoamMatches(matches []roamMatch) {

FILE: internal/server/follow.go
  constant checksumsz (line 17) | checksumsz = 512 * 1024
  method cmdFollow (line 19) | func (s *Server) cmdFollow(msg *Message) (res resp.Value, err error) {
  method cmdReplConf (line 99) | func (s *Server) cmdReplConf(msg *Message, client *Client) (res resp.Val...
  function doServer (line 149) | func doServer(conn *RESPConn) (map[string]string, error) {
  method followHandleCommand (line 165) | func (s *Server) followHandleCommand(args []string, followc int, w io.Wr...
  method followDoLeaderAuth (line 192) | func (s *Server) followDoLeaderAuth(conn *RESPConn, auth string) error {
  constant bitCaughtUpOnce (line 208) | bitCaughtUpOnce int32 = 1
  constant bitCaughtUp (line 209) | bitCaughtUp     int32 = 2
  method setCaughtUp (line 212) | func (s *Server) setCaughtUp(caughtUp bool) {
  method caughtUp (line 222) | func (s *Server) caughtUp() bool {
  method caughtUpOnce (line 226) | func (s *Server) caughtUpOnce() bool {
  method followStep (line 230) | func (s *Server) followStep(host string, port int, followc int) error {
  method follow (line 372) | func (s *Server) follow(host string, port int, followc int) {

FILE: internal/server/group.go
  function byGroupHook (line 7) | func byGroupHook(va, vb interface{}) bool {
  function byGroupObject (line 24) | func byGroupObject(va, vb interface{}) bool {
  type groupItem (line 41) | type groupItem struct
  function newGroupItem (line 48) | func newGroupItem(hookName, colKey, objID string) *groupItem {
  method groupConnect (line 65) | func (s *Server) groupConnect(hookName, colKey, objID string) (groupID s...
  method groupDisconnect (line 72) | func (s *Server) groupDisconnect(hookName, colKey, objID string) {
  method groupGet (line 82) | func (s *Server) groupGet(hookName, colKey, objID string) (groupID strin...
  function deleteGroups (line 94) | func deleteGroups(s *Server, groups []*groupItem) {
  method groupDisconnectObject (line 104) | func (s *Server) groupDisconnectObject(colKey, objID string) {
  method groupDisconnectCollection (line 121) | func (s *Server) groupDisconnectCollection(colKey string) {
  method groupDisconnectHook (line 137) | func (s *Server) groupDisconnectHook(hookName string) {

FILE: internal/server/hooks.go
  function byHookName (line 26) | func byHookName(a, b interface{}) bool {
  method cmdSetHook (line 30) | func (s *Server) cmdSetHook(msg *Message) (
  function byHookExpires (line 231) | func byHookExpires(a, b interface{}) bool {
  method cmdDELHOOKop (line 243) | func (s *Server) cmdDELHOOKop(name string, channel bool) (updated bool) {
  method cmdDelHook (line 274) | func (s *Server) cmdDelHook(msg *Message) (
  method cmdPDelHook (line 305) | func (s *Server) cmdPDelHook(msg *Message) (
  method forEachHookByPattern (line 347) | func (s *Server) forEachHookByPattern(
  method cmdHooks (line 367) | func (s *Server) cmdHooks(msg *Message) (
  type Hook (line 473) | type Hook struct
    method Expires (line 494) | func (h *Hook) Expires() time.Time {
    method Equals (line 499) | func (h *Hook) Equals(hook *Hook) bool {
    method Open (line 552) | func (h *Hook) Open() {
    method Close (line 568) | func (h *Hook) Close() {
    method Signal (line 584) | func (h *Hook) Signal() {
    method manager (line 597) | func (h *Hook) manager() {
    method proc (line 630) | func (h *Hook) proc() (ok bool) {
  type FenceMeta (line 532) | type FenceMeta struct
  type hookMetaByName (line 536) | type hookMetaByName
    method Len (line 538) | func (arr hookMetaByName) Len() int {
    method Less (line 542) | func (arr hookMetaByName) Less(a, b int) bool {
    method Swap (line 546) | func (arr hookMetaByName) Swap(a, b int) {

FILE: internal/server/json.go
  function appendJSONString (line 19) | func appendJSONString(b []byte, s string) []byte {
  function jsonString (line 32) | func jsonString(s string) string {
  function isJSONNumber (line 46) | func isJSONNumber(data string) bool {
  function appendJSONSimpleBounds (line 122) | func appendJSONSimpleBounds(dst []byte, o geojson.Object) []byte {
  function appendJSONSimplePoint (line 136) | func appendJSONSimplePoint(dst []byte, o geojson.Object) []byte {
  function appendJSONTimeFormat (line 151) | func appendJSONTimeFormat(b []byte, t time.Time) []byte {
  function jsonTimeFormat (line 158) | func jsonTimeFormat(t time.Time) string {
  method cmdJget (line 164) | func (s *Server) cmdJget(msg *Message) (resp.Value, error) {
  method cmdJset (line 235) | func (s *Server) cmdJset(msg *Message) (res resp.Value, d commandDetails...
  method cmdJdel (line 323) | func (s *Server) cmdJdel(msg *Message) (res resp.Value, d commandDetails...

FILE: internal/server/json_test.go
  function BenchmarkJSONString (line 8) | func BenchmarkJSONString(t *testing.B) {
  function BenchmarkJSONMarshal (line 15) | func BenchmarkJSONMarshal(t *testing.B) {
  function TestIsJsonNumber (line 22) | func TestIsJsonNumber(t *testing.T) {

FILE: internal/server/keys.go
  method cmdKEYS (line 13) | func (s *Server) cmdKEYS(msg *Message) (resp.Value, error) {

FILE: internal/server/live.go
  type liveBuffer (line 17) | type liveBuffer struct
  method processLives (line 25) | func (s *Server) processLives(wg *sync.WaitGroup) {
  function writeLiveMessage (line 65) | func writeLiveMessage(
  method goLive (line 91) | func (s *Server) goLive(

FILE: internal/server/metrics.go
  method MetricsIndexHandler (line 58) | func (s *Server) MetricsIndexHandler(w http.ResponseWriter, r *http.Requ...
  method MetricsHandler (line 66) | func (s *Server) MetricsHandler(w http.ResponseWriter, r *http.Request) {
  method Describe (line 80) | func (s *Server) Describe(ch chan<- *prometheus.Desc) {
  method Collect (line 86) | func (s *Server) Collect(ch chan<- prometheus.Metric) {
  function toFloat (line 153) | func toFloat(val interface{}) (float64, bool) {

FILE: internal/server/monitor.go
  type liveMonitorSwitches (line 14) | type liveMonitorSwitches struct
    method Error (line 18) | func (sub liveMonitorSwitches) Error() string {
  method cmdMonitor (line 22) | func (s *Server) cmdMonitor(msg *Message) (resp.Value, error) {
  method liveMonitor (line 29) | func (s *Server) liveMonitor(conn net.Conn, rd *PipelineReader, msg *Mes...
  method sendMonitor (line 61) | func (s *Server) sendMonitor(err error, msg *Message, c *Client, lua boo...

FILE: internal/server/must.go
  function Must (line 3) | func Must[T any](a T, err error) T {
  function Default (line 10) | func Default[T comparable](a, b T) T {

FILE: internal/server/must_test.go
  function TestMust (line 8) | func TestMust(t *testing.T) {
  function TestDefault (line 31) | func TestDefault(t *testing.T) {

FILE: internal/server/mvt.go
  type mvtObj (line 12) | type mvtObj struct
  function mvtDrawRing (line 17) | func mvtDrawRing(f *mvt.Feature, tileX, tileY, tileZ int, ring geometry....
  function mvtAddFeature (line 44) | func mvtAddFeature(l *mvt.Layer, tileX, tileY, tileZ int, o mvtObj) {
  function mvtRender (line 97) | func mvtRender(tileX, tileY, tileZ int, objs []mvtObj) []byte {
  function mvtFilterHTTPArgs (line 107) | func mvtFilterHTTPArgs(msg *Message, query string) (modified bool) {

FILE: internal/server/mvt_test.go
  function ls (line 12) | func ls(points []geometry.Point) *geojson.LineString {
  function TestMVTAddFeatureLineStringUsesAllPoints (line 18) | func TestMVTAddFeatureLineStringUsesAllPoints(t *testing.T) {
  function TestMVTAddFeatureLineStringTooShort (line 60) | func TestMVTAddFeatureLineStringTooShort(t *testing.T) {

FILE: internal/server/output.go
  method cmdOUTPUT (line 11) | func (s *Server) cmdOUTPUT(msg *Message) (resp.Value, error) {

FILE: internal/server/pubqueue.go
  type pubQueue (line 10) | type pubQueue struct
  type pubQueueEntry (line 16) | type pubQueueEntry struct
  method startPublishQueue (line 21) | func (s *Server) startPublishQueue(wg *sync.WaitGroup) {
  method stopPublishQueue (line 63) | func (s *Server) stopPublishQueue() {
  method sendPublishQueue (line 70) | func (s *Server) sendPublishQueue(channel string, message ...string) {

FILE: internal/server/pubsub.go
  constant pubsubChannel (line 18) | pubsubChannel = iota
  constant pubsubPattern (line 19) | pubsubPattern
  type pubsub (line 22) | type pubsub struct
    method register (line 83) | func (ps *pubsub) register(kind int, channel string, target *subtarget) {
    method unregister (line 94) | func (ps *pubsub) unregister(kind int, channel string, target *subtarg...
  function newPubsub (line 27) | func newPubsub() *pubsub {
  method Publish (line 37) | func (s *Server) Publish(channel string, message ...string) int {
  type submsg (line 106) | type submsg struct
  type subtarget (line 114) | type subtarget struct
  function newSubtarget (line 120) | func newSubtarget() *subtarget {
  type subhub (line 126) | type subhub struct
  function newSubhub (line 130) | func newSubhub() *subhub {
  type liveSubscriptionSwitches (line 136) | type liveSubscriptionSwitches struct
    method Error (line 140) | func (sub liveSubscriptionSwitches) Error() string {
  method cmdSubscribe (line 144) | func (s *Server) cmdSubscribe(msg *Message) (resp.Value, error) {
  method cmdPsubscribe (line 151) | func (s *Server) cmdPsubscribe(msg *Message) (resp.Value, error) {
  method cmdPublish (line 158) | func (s *Server) cmdPublish(msg *Message) (resp.Value, error) {
  method liveSubscription (line 180) | func (s *Server) liveSubscription(

FILE: internal/server/readonly.go
  method cmdREADONLY (line 11) | func (s *Server) cmdREADONLY(msg *Message) (resp.Value, error) {

FILE: internal/server/respconn.go
  type RESPConn (line 11) | type RESPConn struct
    method Close (line 32) | func (conn *RESPConn) Close() error {
    method Do (line 38) | func (conn *RESPConn) Do(commandName string, args ...interface{}) (
  function DialTimeout (line 18) | func DialTimeout(address string, timeout time.Duration) (*RESPConn, erro...

FILE: internal/server/scan.go
  method cmdScanArgs (line 11) | func (s *Server) cmdScanArgs(vs []string) (
  method cmdScan (line 27) | func (s *Server) cmdScan(msg *Message) (res resp.Value, err error) {

FILE: internal/server/scanner.go
  constant limitItems (line 23) | limitItems = 100
  type outputT (line 25) | type outputT
  constant outputUnknown (line 28) | outputUnknown outputT = iota
  constant outputIDs (line 29) | outputIDs
  constant outputObjects (line 30) | outputObjects
  constant outputCount (line 31) | outputCount
  constant outputPoints (line 32) | outputPoints
  constant outputHashes (line 33) | outputHashes
  constant outputBounds (line 34) | outputBounds
  type scanWriter (line 37) | type scanWriter struct
    method hasFieldsOutput (line 131) | func (sw *scanWriter) hasFieldsOutput() bool {
    method writeFoot (line 140) | func (sw *scanWriter) writeFoot() {
    method fieldMatch (line 255) | func (sw *scanWriter) fieldMatch(o *object.Object) (bool, error) {
    method globMatch (line 297) | func (sw *scanWriter) globMatch(o *object.Object) (ok, keepGoing bool) {
    method Offset (line 317) | func (sw *scanWriter) Offset() uint64 {
    method Step (line 321) | func (sw *scanWriter) Step(n uint64) {
    method testObject (line 327) | func (sw *scanWriter) testObject(o *object.Object,
    method pushObject (line 340) | func (sw *scanWriter) pushObject(opts ScanWriterParams) (keepGoing bool,
    method writeObject (line 386) | func (sw *scanWriter) writeObject(opts ScanWriterParams) {
    method writeFilled (line 395) | func (sw *scanWriter) writeFilled(opts ScanWriterParams) {
  type ScanWriterParams (line 71) | type ScanWriterParams struct
  method newScanWriter (line 81) | func (s *Server) newScanWriter(
  function extractZCoordinate (line 217) | func extractZCoordinate(o geojson.Object) float64 {
  function isPathKey (line 230) | func isPathKey(s string, key string) bool {
  function getFieldValue (line 234) | func getFieldValue(o *object.Object, name string) field.Value {

FILE: internal/server/scanner_test.go
  type testPointItem (line 16) | type testPointItem struct
  function PO (line 21) | func PO(x, y float64) *geojson.Point {
  function BenchmarkFieldMatch (line 25) | func BenchmarkFieldMatch(t *testing.B) {

FILE: internal/server/scripts.go
  constant iniLuaPoolSize (line 26) | iniLuaPoolSize = 5
  constant maxLuaPoolSize (line 27) | maxLuaPoolSize = 1000
  type lStatePool (line 42) | type lStatePool struct
    method Get (line 63) | func (pl *lStatePool) Get() (*lua.LState, error) {
    method Prune (line 80) | func (pl *lStatePool) Prune() {
    method New (line 97) | func (pl *lStatePool) New() *lua.LState {
    method Put (line 210) | func (pl *lStatePool) Put(L *lua.LState) {
    method Shutdown (line 216) | func (pl *lStatePool) Shutdown() {
  method newPool (line 50) | func (s *Server) newPool() *lStatePool {
  type lScriptMap (line 225) | type lScriptMap struct
    method Get (line 231) | func (sm *lScriptMap) Get(key string) (script *lua.FunctionProto, ok b...
    method Put (line 241) | func (sm *lScriptMap) Put(key string, script *lua.FunctionProto) {
    method PutLRU (line 247) | func (sm *lScriptMap) PutLRU(key string, script *lua.FunctionProto) {
    method Flush (line 253) | func (sm *lScriptMap) Flush() {
  method newScriptMap (line 261) | func (s *Server) newScriptMap() *lScriptMap {
  function ConvertToLua (line 268) | func ConvertToLua(L *lua.LState, val resp.Value) lua.LValue {
  function ConvertToRESP (line 296) | func ConvertToRESP(val lua.LValue) resp.Value {
  function ConvertToJSON (line 348) | func ConvertToJSON(val lua.LValue) string {
  function luaSetRawGlobals (line 391) | func luaSetRawGlobals(ls *lua.LState, tbl map[string]lua.LValue) {
  function Sha1Sum (line 399) | func Sha1Sum(s string) string {
  function makeSafeErr (line 406) | func makeSafeErr(err error) error {
  method cmdEvalUnified (line 411) | func (s *Server) cmdEvalUnified(scriptIsSha bool, msg *Message) (res res...
  method cmdScriptLoad (line 531) | func (s *Server) cmdScriptLoad(msg *Message) (resp.Value, error) {
  method cmdScriptExists (line 568) | func (s *Server) cmdScriptExists(msg *Message) (resp.Value, error) {
  method cmdScriptFlush (line 610) | func (s *Server) cmdScriptFlush(msg *Message) (resp.Value, error) {
  method commandInScript (line 626) | func (s *Server) commandInScript(msg *Message) (
  method luaTile38Call (line 693) | func (s *Server) luaTile38Call(evalcmd string, cmd string, args ...strin...
  method luaTile38AtomicRW (line 727) | func (s *Server) luaTile38AtomicRW(msg *Message) (resp.Value, error) {
  method luaTile38AtomicRO (line 786) | func (s *Server) luaTile38AtomicRO(msg *Message) (resp.Value, error) {
  method luaTile38NonAtomic (line 828) | func (s *Server) luaTile38NonAtomic(msg *Message) (resp.Value, error) {
  function openBaseSubset (line 893) | func openBaseSubset(L *lua.LState) int {
  function openOsSubset (line 910) | func openOsSubset(L *lua.LState) int {
  function baseToNumber (line 921) | func baseToNumber(L *lua.LState) int {
  function baseToString (line 953) | func baseToString(L *lua.LState) int {
  function osClock (line 960) | func osClock(L *lua.LState) int {
  function osDiffTime (line 966) | func osDiffTime(L *lua.LState) int {

FILE: internal/server/search.go
  constant defaultCircleSteps (line 23) | defaultCircleSteps = 64
  type liveFenceSwitches (line 25) | type liveFenceSwitches struct
    method Error (line 47) | func (lfs liveFenceSwitches) Error() string {
    method Close (line 51) | func (lfs liveFenceSwitches) Close() {
    method usingLua (line 57) | func (lfs liveFenceSwitches) usingLua() bool {
  type roamSwitches (line 32) | type roamSwitches struct
  type roamMatch (line 41) | type roamMatch struct
  function parseRectArea (line 61) | func parseRectArea(ltyp string, vs []string) (nvs []string,
  method cmdSearchArgs (line 198) | func (s *Server) cmdSearchArgs(
  method cmdNearby (line 501) | func (s *Server) cmdNearby(msg *Message) (res resp.Value, err error) {
  method cmdWITHIN (line 591) | func (s *Server) cmdWITHIN(msg *Message) (res resp.Value, err error) {
  method cmdINTERSECTS (line 595) | func (s *Server) cmdINTERSECTS(msg *Message) (res resp.Value, err error) {
  method cmdWITHINorINTERSECTS (line 599) | func (s *Server) cmdWITHINorINTERSECTS(cmd string, msg *Message) (res re...
  method cmdSeachValuesArgs (line 675) | func (s *Server) cmdSeachValuesArgs(vs []string) (
  function multiGlobParse (line 691) | func multiGlobParse(globs []string, desc bool) [2]string {
  method cmdSearch (line 720) | func (s *Server) cmdSearch(msg *Message) (res resp.Value, err error) {

FILE: internal/server/server.go
  function errTimeoutOnCmd (line 46) | func errTimeoutOnCmd(cmd string) error {
  constant goingLive (line 51) | goingLive     = "going live"
  constant hookLogPrefix (line 52) | hookLogPrefix = "hook:log:"
  type commandDetails (line 57) | type commandDetails struct
  type rwlocker (line 72) | type rwlocker interface
  type rwspinlock (line 81) | type rwspinlock struct
    method Lock (line 85) | func (l *rwspinlock) Lock() {
    method LockLowPriority (line 94) | func (l *rwspinlock) LockLowPriority() {
    method Unlock (line 98) | func (l *rwspinlock) Unlock() {
    method RLock (line 103) | func (l *rwspinlock) RLock() {
    method RUnlock (line 112) | func (l *rwspinlock) RUnlock() {
  type rwmutex (line 120) | type rwmutex struct
    method Lock (line 124) | func (l *rwmutex) Lock() {
    method LockLowPriority (line 139) | func (l *rwmutex) LockLowPriority() {
    method Unlock (line 144) | func (l *rwmutex) Unlock() {
    method RLock (line 147) | func (l *rwmutex) RLock() {
    method RUnlock (line 150) | func (l *rwmutex) RUnlock() {
  type Server (line 155) | type Server struct
    method isProtected (line 541) | func (s *Server) isProtected() bool {
    method netServe (line 555) | func (s *Server) netServe() error {
    method watchAutoGC (line 846) | func (s *Server) watchAutoGC(wg *sync.WaitGroup) {
    method checkOutOfMemory (line 873) | func (s *Server) checkOutOfMemory() {
    method loopUntilServerStops (line 892) | func (s *Server) loopUntilServerStops(dur time.Duration, op func()) {
    method watchOutOfMemory (line 907) | func (s *Server) watchOutOfMemory(wg *sync.WaitGroup) {
    method watchLuaStatePool (line 914) | func (s *Server) watchLuaStatePool(wg *sync.WaitGroup) {
    method backgroundSyncAOF (line 922) | func (s *Server) backgroundSyncAOF(wg *sync.WaitGroup) {
    method handleInputCommand (line 959) | func (s *Server) handleInputCommand(client *Client, msg *Message) error {
    method reset (line 1318) | func (s *Server) reset() {
    method command (line 1323) | func (s *Server) command(msg *Message, client *Client) (
  type Options (line 240) | type Options struct
  function Serve (line 275) | func Serve(opts Options) error {
  type liveConn (line 810) | type liveConn struct
    method Close (line 815) | func (conn *liveConn) Close() error {
    method LocalAddr (line 819) | func (conn *liveConn) LocalAddr() net.Addr {
    method RemoteAddr (line 823) | func (conn *liveConn) RemoteAddr() net.Addr {
    method Read (line 826) | func (conn *liveConn) Read(b []byte) (n int, err error) {
    method Write (line 830) | func (conn *liveConn) Write(b []byte) (n int, err error) {
    method SetDeadline (line 834) | func (conn *liveConn) SetDeadline(deadline time.Time) error {
    method SetReadDeadline (line 838) | func (conn *liveConn) SetReadDeadline(deadline time.Time) error {
    method SetWriteDeadline (line 842) | func (conn *liveConn) SetWriteDeadline(deadline time.Time) error {
  function isReservedFieldName (line 931) | func isReservedFieldName(field string) bool {
  function rewriteTimeoutMsg (line 939) | func rewriteTimeoutMsg(msg *Message) (err error) {
  function randomKey (line 1306) | func randomKey(n int) string {
  function WriteWebSocketMessage (line 1507) | func WriteWebSocketMessage(w io.Writer, data []byte) error {
  function OKMessage (line 1531) | func OKMessage(msg *Message, start time.Time) resp.Value {
  type Type (line 1547) | type Type
  constant Null (line 1551) | Null Type = iota
  constant RESP (line 1552) | RESP
  constant Telnet (line 1553) | Telnet
  constant Native (line 1554) | Native
  constant HTTP (line 1555) | HTTP
  constant WebSocket (line 1556) | WebSocket
  constant JSON (line 1557) | JSON
  type Message (line 1561) | type Message struct
    method Command (line 1573) | func (msg *Message) Command() string {
  type PipelineReader (line 1581) | type PipelineReader struct
    method ReadMessages (line 1784) | func (rd *PipelineReader) ReadMessages() ([]*Message, error) {
  constant kindHTTP (line 1588) | kindHTTP redcon.Kind = 9999
  function NewPipelineReader (line 1591) | func NewPipelineReader(rd io.ReadWriter) *PipelineReader {
  function readcrlfline (line 1595) | func readcrlfline(packet []byte) (line string, leftover []byte, ok bool) {
  function headerValue (line 1604) | func headerValue(header, name string) int {
  function readNextHTTPCommand (line 1631) | func readNextHTTPCommand(packet []byte, argsIn [][]byte, msg *Message, w...
  function readNextCommand (line 1759) | func readNextCommand(packet []byte, argsIn [][]byte, msg *Message, wr io...
  function readNativeMessageLine (line 1845) | func readNativeMessageLine(line []byte) (*Message, error) {
  type InputStream (line 1884) | type InputStream struct
    method Begin (line 1888) | func (is *InputStream) Begin(packet []byte) (data []byte) {
    method End (line 1898) | func (is *InputStream) End(data []byte) {
  function clientErrorf (line 1912) | func clientErrorf(format string, args ...interface{}) error {

FILE: internal/server/stats.go
  function readMemStats (line 27) | func readMemStats() runtime.MemStats {
  method cmdSTATS (line 49) | func (s *Server) cmdSTATS(msg *Message) (resp.Value, error) {
  method cmdHEALTHZ (line 99) | func (s *Server) cmdHEALTHZ(msg *Message) (resp.Value, error) {
  method cmdSERVER (line 127) | func (s *Server) cmdSERVER(msg *Message) (resp.Value, error) {
  method basicStats (line 164) | func (s *Server) basicStats(m map[string]interface{}) {
  method extStats (line 227) | func (s *Server) extStats(m map[string]interface{}) {
  method writeInfoServer (line 390) | func (s *Server) writeInfoServer(w *bytes.Buffer) {
  method writeInfoClients (line 395) | func (s *Server) writeInfoClients(w *bytes.Buffer) {
  method writeInfoMemory (line 400) | func (s *Server) writeInfoMemory(w *bytes.Buffer) {
  function boolInt (line 404) | func boolInt(t bool) int {
  method writeInfoPersistence (line 410) | func (s *Server) writeInfoPersistence(w *bytes.Buffer) {
  method writeInfoStats (line 423) | func (s *Server) writeInfoStats(w *bytes.Buffer) {
  function replicaIPAndPort (line 430) | func replicaIPAndPort(cc *Client) (ip string, port int) {
  method writeInfoReplication (line 447) | func (s *Server) writeInfoReplication(w *bytes.Buffer) {
  method writeInfoCluster (line 473) | func (s *Server) writeInfoCluster(w *bytes.Buffer) {
  method cmdINFO (line 478) | func (s *Server) cmdINFO(msg *Message) (res resp.Value, err error) {
  function tryParseType (line 581) | func tryParseType(str string) interface{} {
  function respValuesSimpleMap (line 594) | func respValuesSimpleMap(m map[string]interface{}) []resp.Value {
  method cmdROLE (line 610) | func (s *Server) cmdROLE(msg *Message) (res resp.Value, err error) {

FILE: internal/server/stats_cpu.go
  method writeInfoCPU (line 10) | func (s *Server) writeInfoCPU(w *bytes.Buffer) {

FILE: internal/server/stats_cpu_darlin.go
  method writeInfoCPU (line 11) | func (s *Server) writeInfoCPU(w *bytes.Buffer) {

FILE: internal/server/test.go
  method parseArea (line 21) | func (s *Server) parseArea(ovs []string, doClip bool) (vs []string, o ge...
  method cmdTEST (line 297) | func (s *Server) cmdTEST(msg *Message) (res resp.Value, err error) {

FILE: internal/server/token.go
  constant defaultSearchOutput (line 16) | defaultSearchOutput = outputObjects
  function errInvalidArgument (line 27) | func errInvalidArgument(arg string) error {
  function errDuplicateArgument (line 30) | func errDuplicateArgument(arg string) error {
  function token (line 33) | func token(line string) (newLine, token string) {
  function tokenval (line 42) | func tokenval(vs []string) (nvs []string, token string, ok bool) {
  function lc (line 51) | func lc(s1, s2 string) bool {
  type whereT (line 68) | type whereT struct
    method matchField (line 83) | func (where whereT) matchField(value field.Value) bool {
  function mLT (line 77) | func mLT(a, b field.Value) bool  { return a.Less(b) }
  function mLTE (line 78) | func mLTE(a, b field.Value) bool { return !mLT(b, a) }
  function mGT (line 79) | func mGT(a, b field.Value) bool  { return mLT(b, a) }
  function mGTE (line 80) | func mGTE(a, b field.Value) bool { return !mLT(a, b) }
  function mEQ (line 81) | func mEQ(a, b field.Value) bool  { return a.Equals(b) }
  type whereinT (line 119) | type whereinT struct
    method match (line 124) | func (wherein whereinT) match(value field.Value) bool {
  type whereevalT (line 133) | type whereevalT struct
    method Close (line 139) | func (whereeval whereevalT) Close() {
    method match (line 164) | func (whereeval whereevalT) match(fieldsWithNames map[string]field.Value,
  function luaSetField (line 147) | func luaSetField(tbl *lua.LTable, name string, val field.Value) {
  type searchScanBaseTokens (line 231) | type searchScanBaseTokens struct
  method parseSearchScanBaseTokens (line 260) | func (s *Server) parseSearchScanBaseTokens(
  function detectExprToken (line 725) | func detectExprToken(vs []string) bool {
  type parentStack (line 744) | type parentStack
    method isEmpty (line 746) | func (ps *parentStack) isEmpty() bool {
    method push (line 750) | func (ps *parentStack) push(e *areaExpression) {
    method pop (line 754) | func (ps *parentStack) pop() (e *areaExpression, empty bool) {
  method parseAreaExpression (line 764) | func (s *Server) parseAreaExpression(vsin []string, doClip bool) (vsout ...

FILE: internal/server/token_test.go
  function TestLowerCompare (line 10) | func TestLowerCompare(t *testing.T) {
  function TestParseWhereins (line 34) | func TestParseWhereins(t *testing.T) {
  function BenchmarkLowerCompare (line 190) | func BenchmarkLowerCompare(t *testing.B) {
  function BenchmarkStringsLowerCompare (line 198) | func BenchmarkStringsLowerCompare(t *testing.B) {

FILE: internal/sstring/sstring.go
  function Load (line 17) | func Load(num int) (str string) {
  function Store (line 31) | func Store(str string) (num int) {
  function Len (line 49) | func Len() int {

FILE: internal/sstring/sstring_test.go
  function TestShared (line 11) | func TestShared(t *testing.T) {
  function randStr (line 39) | func randStr(n int) string {
  function BenchmarkStore (line 48) | func BenchmarkStore(b *testing.B) {
  function BenchmarkLoad (line 64) | func BenchmarkLoad(b *testing.B) {

FILE: internal/viewer/viewer.go
  function HandleHTTP (line 18) | func HandleHTTP(wr io.Writer, url string, devMode bool) error {
  function writeHTTPFile (line 36) | func writeHTTPFile(wr io.Writer, path string, devMode bool) error {
  function writeHTTPResponse (line 54) | func writeHTTPResponse(wr io.Writer, status, contentType string,

FILE: tests/107/main.go
  constant tile38Port (line 26) | tile38Port = 9191
  constant httpPort (line 27) | httpPort = 9292
  constant dir (line 28) | dir = "data"
  constant blank (line 49) | blank = false
  constant hookServer (line 50) | hookServer = true
  function main (line 54) | func main() {
  function startTile38Server (line 101) | func startTile38Server() {
  function startHookServer (line 116) | func startHookServer() {
  function waitForServers (line 134) | func waitForServers(cb func()) {
  function downloadAOF (line 186) | func downloadAOF() {
  function copyAOF (line 224) | func copyAOF() {
  function respGet (line 267) | func respGet(resp interface{}, idx ...int) interface{} {
  type PSAUX (line 275) | type PSAUX struct
  function atoi (line 289) | func atoi(s string) int {
  function atof (line 293) | func atof(s string) float64 {
  function psaux (line 297) | func psaux(pid int) PSAUX {
  function respGetFloat (line 331) | func respGetFloat(resp interface{}, idx ...int) float64 {
  function logServer (line 336) | func logServer(tag string) {
  function setPoints (line 362) | func setPoints() {

FILE: tests/616/main.go
  constant exsecs (line 18) | exsecs = 10
  constant key (line 19) | key = "__issue_616__"
  function makeID (line 21) | func makeID() string {
  function main (line 31) | func main() {
  function must (line 128) | func must(v interface{}, err error) interface{} {

FILE: tests/aof_test.go
  function subTestAOF (line 21) | func subTestAOF(g *testGroup) {
  function loadAOFAndClose (line 30) | func loadAOFAndClose(aof any) error {
  function loadAOF (line 38) | func loadAOF(aof any) (*mockServer, error) {
  function aof_loading_test (line 55) | func aof_loading_test(mc *mockServer) error {
  function aof_AOFMD5_test (line 105) | func aof_AOFMD5_test(mc *mockServer) error {
  function openFollower (line 143) | func openFollower(mc *mockServer) (conn redis.Conn, err error) {
  function aof_AOF_test (line 171) | func aof_AOF_test(mc *mockServer) error {
  function aof_AOFSHRINK_test (line 243) | func aof_AOFSHRINK_test(mc *mockServer) error {
  function aof_READONLY_test (line 282) | func aof_READONLY_test(mc *mockServer) error {
  function aof_migrate_test (line 297) | func aof_migrate_test(mc *mockServer) error {

FILE: tests/client_test.go
  function subTestClient (line 13) | func subTestClient(g *testGroup) {
  function client_OUTPUT_test (line 18) | func client_OUTPUT_test(mc *mockServer) error {
  function client_CLIENT_test (line 56) | func client_CLIENT_test(mc *mockServer) error {

FILE: tests/fence_roaming_test.go
  function fence_roaming_webhook_test (line 16) | func fence_roaming_webhook_test(mc *mockServer) error {
  function goMultiFunc (line 86) | func goMultiFunc(mc *mockServer, fns ...func() error) error {
  function fence_roaming_live_test (line 112) | func fence_roaming_live_test(mc *mockServer) error {
  function fence_roaming_channel_test (line 179) | func fence_roaming_channel_test(mc *mockServer) error {
  function cleanMessage (line 261) | func cleanMessage(body []byte) string {
  function roamingTestData (line 270) | func roamingTestData() (car1 [][]float64, car2 [][]float64, output []str...

FILE: tests/fence_test.go
  function subTestFence (line 21) | func subTestFence(g *testGroup) {
  type fenceReader (line 40) | type fenceReader struct
    method receive (line 45) | func (fr *fenceReader) receive() (string, error) {
    method receiveExpect (line 76) | func (fr *fenceReader) receiveExpect(valex ...string) error {
  function fence_basic_test (line 89) | func fence_basic_test(mc *mockServer) error {
  function fence_channel_message_order_test (line 174) | func fence_channel_message_order_test(mc *mockServer) error {
  function fence_detect_inside_test (line 252) | func fence_detect_inside_test(mc *mockServer) error {
  function do (line 317) | func do(c redis.Conn, cmd string) (interface{}, error) {
  function fence_channel_meta_test (line 331) | func fence_channel_meta_test(mc *mockServer) error {
  function dialTile38 (line 349) | func dialTile38(port int) (redis.Conn, error) {
  function doTile38 (line 361) | func doTile38(c redis.Conn, cmd string, args ...interface{}) (string, er...
  function fence_eecio_test (line 369) | func fence_eecio_test(mc *mockServer) error {

FILE: tests/follower_test.go
  function subTestFollower (line 5) | func subTestFollower(g *testGroup) {
  function follower_follow_test (line 9) | func follower_follow_test(mc *mockServer) error {

FILE: tests/json_test.go
  function subTestJSON (line 3) | func subTestJSON(g *testGroup) {
  function json_JSET_basic_test (line 9) | func json_JSET_basic_test(mc *mockServer) error {
  function json_JSET_geojson_test (line 26) | func json_JSET_geojson_test(mc *mockServer) error {
  function json_JSET_number_test (line 43) | func json_JSET_number_test(mc *mockServer) error {

FILE: tests/keys_search_test.go
  function subTestSearch (line 16) | func subTestSearch(g *testGroup) {
  function keys_KNN_basic_test (line 38) | func keys_KNN_basic_test(mc *mockServer) error {
  function keys_KNN_random_test (line 92) | func keys_KNN_random_test(mc *mockServer) error {
  function keys_KNN_cursor_test (line 140) | func keys_KNN_cursor_test(mc *mockServer) error {
  function keys_WITHIN_test (line 162) | func keys_WITHIN_test(mc *mockServer) error {
  function keys_WITHIN_CURSOR_test (line 212) | func keys_WITHIN_CURSOR_test(mc *mockServer) error {
  function keys_WITHIN_CLIPBY_test (line 258) | func keys_WITHIN_CLIPBY_test(mc *mockServer) error {
  function keys_INTERSECTS_test (line 302) | func keys_INTERSECTS_test(mc *mockServer) error {
  function keys_INTERSECTS_CLIPBY_test (line 360) | func keys_INTERSECTS_CLIPBY_test(mc *mockServer) error {
  function keys_INTERSECTS_CURSOR_test (line 404) | func keys_INTERSECTS_CURSOR_test(mc *mockServer) error {
  function keys_WITHIN_CIRCLE_test (line 450) | func keys_WITHIN_CIRCLE_test(mc *mockServer) error {
  function keys_WITHIN_SECTOR_test (line 466) | func keys_WITHIN_SECTOR_test(mc *mockServer) error {
  function keys_NEARBY_SPARSE_test (line 482) | func keys_NEARBY_SPARSE_test(mc *mockServer) error {
  function keys_INTERSECTS_CIRCLE_test (line 565) | func keys_INTERSECTS_CIRCLE_test(mc *mockServer) error {
  function keys_INTERSECTS_SECTOR_test (line 581) | func keys_INTERSECTS_SECTOR_test(mc *mockServer) error {
  function keys_SCAN_CURSOR_test (line 597) | func keys_SCAN_CURSOR_test(mc *mockServer) error {
  function keys_SEARCH_CURSOR_test (line 619) | func keys_SEARCH_CURSOR_test(mc *mockServer) error {
  function keys_MATCH_test (line 642) | func keys_MATCH_test(mc *mockServer) error {
  function keys_FIELDS_search_test (line 696) | func keys_FIELDS_search_test(mc *mockServer) error {
  function keys_BUFFER_search_test (line 761) | func keys_BUFFER_search_test(mc *mockServer) error {
  function match (line 793) | func match(expectIn string) func(org, v interface{}) (resp, expect inter...
  function subBenchSearch (line 803) | func subBenchSearch(b *testing.B, mc *mockServer) {
  function keys_KNN_bench (line 807) | func keys_KNN_bench(mc *mockServer) error {

FILE: tests/keys_test.go
  function subTestKeys (line 14) | func subTestKeys(g *testGroup) {
  function keys_BOUNDS_test (line 43) | func keys_BOUNDS_test(mc *mockServer) error {
  function keys_DEL_test (line 65) | func keys_DEL_test(mc *mockServer) error {
  function keys_DROP_test (line 84) | func keys_DROP_test(mc *mockServer) error {
  function keys_RENAME_test (line 100) | func keys_RENAME_test(mc *mockServer) error {
  function keys_RENAMENX_test (line 128) | func keys_RENAMENX_test(mc *mockServer) error {
  function keys_EXPIRE_test (line 146) | func keys_EXPIRE_test(mc *mockServer) error {
  function keys_FSET_test (line 168) | func keys_FSET_test(mc *mockServer) error {
  function keys_FGET_test (line 235) | func keys_FGET_test(mc *mockServer) error {
  function keys_GET_test (line 254) | func keys_GET_test(mc *mockServer) error {
  function keys_KEYS_test (line 289) | func keys_KEYS_test(mc *mockServer) error {
  function keys_PERSIST_test (line 315) | func keys_PERSIST_test(mc *mockServer) error {
  function keys_SET_test (line 330) | func keys_SET_test(mc *mockServer) error {
  function keys_STATS_test (line 452) | func keys_STATS_test(mc *mockServer) error {
  function keys_TTL_test (line 474) | func keys_TTL_test(mc *mockServer) error {
  function keys_EXISTS_test (line 494) | func keys_EXISTS_test(mc *mockServer) error {
  function keys_FEXISTS_test (line 505) | func keys_FEXISTS_test(mc *mockServer) error {
  function keys_SET_EX_test (line 518) | func keys_SET_EX_test(mc *mockServer) (err error) {
  function keys_FIELDS_test (line 554) | func keys_FIELDS_test(mc *mockServer) error {
  function keys_PDEL_test (line 664) | func keys_PDEL_test(mc *mockServer) error {
  function keys_WHEREIN_test (line 692) | func keys_WHEREIN_test(mc *mockServer) error {
  function keys_WHEREEVAL_test (line 709) | func keys_WHEREEVAL_test(mc *mockServer) error {
  function keys_TYPE_test (line 721) | func keys_TYPE_test(mc *mockServer) error {
  function keys_FLUSHDB_test (line 732) | func keys_FLUSHDB_test(mc *mockServer) error {
  function keys_HEALTHZ_test (line 755) | func keys_HEALTHZ_test(mc *mockServer) error {
  function keys_SERVER_test (line 763) | func keys_SERVER_test(mc *mockServer) error {
  function keys_INFO_test (line 810) | func keys_INFO_test(mc *mockServer) error {

FILE: tests/metrics_test.go
  function subTestMetrics (line 10) | func subTestMetrics(g *testGroup) {
  function downloadURLWithStatusCode (line 14) | func downloadURLWithStatusCode(u string) (int, string, error) {
  function metrics_basic_test (line 27) | func metrics_basic_test(mc *mockServer) error {

FILE: tests/mock_io_test.go
  type IO (line 15) | type IO struct
    method JSON (line 29) | func (cmd *IO) JSON() *IO {
    method Str (line 33) | func (cmd *IO) Str(s string) *IO {
    method Func (line 37) | func (cmd *IO) Func(fn func(s string) error) *IO {
    method OK (line 49) | func (cmd *IO) OK() *IO {
    method Err (line 62) | func (cmd *IO) Err(msg string) *IO {
    method deepError (line 86) | func (cmd *IO) deepError(index int, err error) error {
  function Do (line 25) | func Do(args ...any) *IO {
  function Sleep (line 82) | func Sleep(duration time.Duration) *IO {
  method doIOTest (line 123) | func (mc *mockServer) doIOTest(index int, cmd *IO) error {

FILE: tests/mock_test.go
  function mockCleanup (line 23) | func mockCleanup(silent bool) {
  type mockServer (line 38) | type mockServer struct
    method readAOF (line 48) | func (mc *mockServer) readAOF() ([]byte, error) {
    method metricsPort (line 52) | func (mc *mockServer) metricsPort() int {
    method waitForStartup (line 138) | func (s *mockServer) waitForStartup(ferr *atomic.Pointer[error]) error {
    method Close (line 170) | func (mc *mockServer) Close() {
    method ResetConn (line 184) | func (mc *mockServer) ResetConn() {
    method DoPipeline (line 191) | func (s *mockServer) DoPipeline(cmds [][]interface{}) ([]interface{}, ...
    method Do (line 219) | func (s *mockServer) Do(commandName string, args ...interface{}) (inte...
    method DoBatch (line 232) | func (mc *mockServer) DoBatch(commands ...interface{}) error {
    method DoExpect (line 297) | func (mc *mockServer) DoExpect(expect interface{}, commandName string,...
  type MockServerOptions (line 56) | type MockServerOptions struct
  function getNextPort (line 65) | func getNextPort() int {
  function mockOpenServer (line 77) | func mockOpenServer(opts MockServerOptions) (*mockServer, error) {
  function normalize (line 284) | func normalize(v interface{}) interface{} {

FILE: tests/monitor_test.go
  function subTestMonitor (line 11) | func subTestMonitor(g *testGroup) {
  function follower_monitor_test (line 15) | func follower_monitor_test(mc *mockServer) error {

FILE: tests/proto_test.go
  function subTestProto (line 8) | func subTestProto(g *testGroup) {
  function proto_HTTP_CORS_test (line 12) | func proto_HTTP_CORS_test(mc *mockServer) error {

FILE: tests/scripts_test.go
  function subTestScripts (line 8) | func subTestScripts(g *testGroup) {
  function scripts_BASIC_test (line 16) | func scripts_BASIC_test(mc *mockServer) error {
  function scripts_ATOMIC_test (line 32) | func scripts_ATOMIC_test(mc *mockServer) error {
  function scripts_READONLY_test (line 40) | func scripts_READONLY_test(mc *mockServer) error {
  function scripts_NONATOMIC_test (line 58) | func scripts_NONATOMIC_test(mc *mockServer) error {
  function scripts_VULN_test (line 66) | func scripts_VULN_test(mc *mockServer) error {

FILE: tests/stats_test.go
  function subTestInfo (line 9) | func subTestInfo(g *testGroup) {
  function info_valid_json_test (line 13) | func info_valid_json_test(mc *mockServer) error {

FILE: tests/testcmd_test.go
  function subTestTestCmd (line 3) | func subTestTestCmd(g *testGroup) {
  function testcmd_WITHIN_test (line 11) | func testcmd_WITHIN_test(mc *mockServer) error {
  function testcmd_INTERSECTS_test (line 124) | func testcmd_INTERSECTS_test(mc *mockServer) error {
  function testcmd_INTERSECTS_CLIP_test (line 168) | func testcmd_INTERSECTS_CLIP_test(mc *mockServer) error {
  function testcmd_expressionErrors_test (line 192) | func testcmd_expressionErrors_test(mc *mockServer) error {
  function testcmd_expression_test (line 218) | func testcmd_expression_test(mc *mockServer) error {

FILE: tests/tests_test.go
  constant clear (line 21) | clear   = "\x1b[0m"
  constant bright (line 22) | bright  = "\x1b[1m"
  constant dim (line 23) | dim     = "\x1b[2m"
  constant black (line 24) | black   = "\x1b[30m"
  constant red (line 25) | red     = "\x1b[31m"
  constant green (line 26) | green   = "\x1b[32m"
  constant yellow (line 27) | yellow  = "\x1b[33m"
  constant blue (line 28) | blue    = "\x1b[34m"
  constant magenta (line 29) | magenta = "\x1b[35m"
  constant cyan (line 30) | cyan    = "\x1b[36m"
  constant white (line 31) | white   = "\x1b[37m"
  function TestIntegration (line 34) | func TestIntegration(t *testing.T) {
  function runTestGroups (line 66) | func runTestGroups(t *testing.T) {
  type testGroup (line 194) | type testGroup struct
    method regSubTest (line 217) | func (g *testGroup) regSubTest(name string, fn func(mc *mockServer) er...
  type testGroupSub (line 200) | type testGroupSub struct
    method run (line 222) | func (s *testGroupSub) run() (err error) {
  function regTestGroup (line 211) | func regTestGroup(name string, fn func(g *testGroup)) {
  function BenchmarkAll (line 241) | func BenchmarkAll(b *testing.B) {
  function loadBenchmarkPoints (line 263) | func loadBenchmarkPoints(b *testing.B, mc *mockServer) (err error) {
  function runSubBenchmark (line 290) | func runSubBenchmark(b *testing.B, name string, mc *mockServer, bench fu...
  function runBenchStep (line 296) | func runBenchStep(b *testing.B, mc *mockServer, name string, step func(m...

FILE: tests/timeout_test.go
  function subTestTimeout (line 12) | func subTestTimeout(g *testGroup) {
  function setup (line 21) | func setup(mc *mockServer, count int, points bool) (err error) {
  function timeout_spatial_test (line 56) | func timeout_spatial_test(mc *mockServer) error {
  function timeout_search_test (line 72) | func timeout_search_test(mc *mockServer) (err error) {
  function timeout_scripts_test (line 84) | func timeout_scripts_test(mc *mockServer) (err error) {
  function timeout_no_writes_test (line 112) | func timeout_no_writes_test(mc *mockServer) (err error) {
  function scriptTimeoutErr (line 119) | func scriptTimeoutErr(v interface{}) (resp, expect interface{}) {
  function timeout_within_scripts_test (line 127) | func timeout_within_scripts_test(mc *mockServer) (err error) {
  function scriptTimeoutNotSupportedErr (line 151) | func scriptTimeoutNotSupportedErr(v interface{}) (resp, expect interface...
  function timeout_no_writes_within_scripts_test (line 159) | func timeout_no_writes_within_scripts_test(mc *mockServer) (err error) {
Condensed preview — 152 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,187K chars).
[
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 1482,
    "preview": "## How to contribute to Tile38\n\nBefore getting starting with contributing, please know that we currently use [Tile38 Sla"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 698,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 297,
    "preview": "blank_issues_enabled: true\ncontact_links:\n  - name: Community Support\n    url: https://tile38.com/slack/\n    about: Plea"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 522,
    "preview": "Please do not open a pull request without first filing an issue and/or discussing the feature directly with the project "
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 651,
    "preview": "name: Go\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\njobs:\n  build:\n    name: Build\n    "
  },
  {
    "path": ".gitignore",
    "chars": 108,
    "preview": ".DS_Store\ntile38-*\n!cmd/tile38-*\n*.test\ndata*/\ncoverage.out\npackages/\n\n# Ignore IDE folders\n.idea/\n.vscode/\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 25634,
    "preview": "# Change Log\nAll notable changes to this project will be documented in this file.\nThis project adheres to [Semantic Vers"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1555,
    "preview": "# Contributing\n\nThanks for your interest in improving Tile38!\n\n## Issues\n- **Found a bug?** Please open an issue with a "
  },
  {
    "path": "Dockerfile",
    "chars": 514,
    "preview": "FROM alpine:3.20\n\nARG VERSION\nARG TARGETOS\nARG TARGETARCH\n\nRUN apk add --no-cache ca-certificates\n\nADD packages/tile38-$"
  },
  {
    "path": "LICENSE",
    "chars": 1054,
    "preview": "Copyright (c) 2016 Josh Baker\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this soft"
  },
  {
    "path": "Makefile",
    "chars": 1032,
    "preview": "all: tile38-server tile38-cli tile38-benchmark tile38-luamemtest\n\n.PHONY: tile38-server\ntile38-server:\n\t@./scripts/build"
  },
  {
    "path": "README.md",
    "chars": 17645,
    "preview": "<p align=\"center\">\n<picture>\n  <source media=\"(prefers-color-scheme: dark)\" srcset=\"/.github/images/logo-dark.svg\">\n  <s"
  },
  {
    "path": "cmd/tile38-benchmark/az/az.go",
    "chars": 45145,
    "preview": "package az\n\n// JSON is GeoJSON\nvar JSON = `\n{ \"type\": \"MultiPolygon\", \"coordinates\": [ [ [ [ -114.635458, 34.876902 ], ["
  },
  {
    "path": "cmd/tile38-benchmark/main.go",
    "chars": 23857,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"ti"
  },
  {
    "path": "cmd/tile38-cli/main.go",
    "chars": 16059,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath"
  },
  {
    "path": "cmd/tile38-luamemtest/main.go",
    "chars": 7163,
    "preview": "package main\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\n\t\"strings\"\n\n"
  },
  {
    "path": "cmd/tile38-server/main.go",
    "chars": 12999,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t_ \"net/http/pprof\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t"
  },
  {
    "path": "core/commands.go",
    "chars": 3926,
    "preview": "//go:build ignore\n\npackage core\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n)\n\nconst (\n\tclear  = \"\\x1b[0m\"\n\tbright = \"\\x1b[1m\""
  },
  {
    "path": "core/commands.json",
    "chars": 45291,
    "preview": "{\n  \"SET\": {\n    \"summary\": \"Sets the value of an id\",\n    \"complexity\": \"O(1)\",\n    \"arguments\": [\n      {\n        \"nam"
  },
  {
    "path": "core/commands_gen.go",
    "chars": 49226,
    "preview": "// This file was autogenerated. DO NOT EDIT.\n\npackage core\n\nimport (\n\t\"encoding/json\"\n\t\"strings\"\n)\n\nconst (\n\tclear  = \"\\"
  },
  {
    "path": "core/commands_test.go",
    "chars": 319,
    "preview": "package core\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"testing\"\n)\n\nfunc TestCommands(t *testing.T) {\n\tvar names []string\n\tfor name := r"
  },
  {
    "path": "core/gen.sh",
    "chars": 429,
    "preview": "#!/bin/sh\n\nset -e\n\ncd $(dirname $0)\nexport CommandsJSON=\"$(cat commands.json)\"\n\n# replace out the json\nperl -pe '\n    wh"
  },
  {
    "path": "core/version.go",
    "chars": 206,
    "preview": "package core\n\n// Build variables\nvar (\n\tVersion   = \"0.0.0\"   // Placeholder for the version\n\tBuildTime = \"\"        // P"
  },
  {
    "path": "go.mod",
    "chars": 5723,
    "preview": "module github.com/tidwall/tile38\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/tidwall/assert v0.1.0\n\tgithub.com/tidwall/btree v1.8."
  },
  {
    "path": "go.sum",
    "chars": 39893,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.121.4 h1:cVvUi"
  },
  {
    "path": "internal/bing/bing.go",
    "chars": 6836,
    "preview": "// https://msdn.microsoft.com/en-us/library/bb259689.aspx\n\npackage bing\n\nimport \"math\"\n\nconst (\n\t// EarthRadius is the r"
  },
  {
    "path": "internal/bing/bing_test.go",
    "chars": 2793,
    "preview": "package bing\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestLevelFuzz(t *testing.T) {\n\trand.Seed(time.Now().UnixN"
  },
  {
    "path": "internal/bing/ext.go",
    "chars": 1730,
    "preview": "package bing\n\nimport \"errors\"\n\n// LatLongToQuad iterates through all of the quads parts until levelOfDetail is reached.\n"
  },
  {
    "path": "internal/bing/ext_test.go",
    "chars": 2450,
    "preview": "package bing\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestIteratorFuzz(t *testing.T) {\n\trand.Seed(time.Now().Un"
  },
  {
    "path": "internal/buffer/buffer.go",
    "chars": 5172,
    "preview": "package buffer\n\nimport (\n\t\"errors\"\n\t\"math\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geo\"\n\t\"github.com"
  },
  {
    "path": "internal/buffer/buffer_test.go",
    "chars": 3220,
    "preview": "package buffer\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nconst lineS"
  },
  {
    "path": "internal/clip/clip.go",
    "chars": 3810,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\n// Clip clips the content"
  },
  {
    "path": "internal/clip/clip_test.go",
    "chars": 4899,
    "preview": "package clip\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc LO(point"
  },
  {
    "path": "internal/clip/collection.go",
    "chars": 569,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipCollection(\n\tcol"
  },
  {
    "path": "internal/clip/feature.go",
    "chars": 403,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipFeature(\n\tfeatur"
  },
  {
    "path": "internal/clip/linestring.go",
    "chars": 1091,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipLineString(\n\tlin"
  },
  {
    "path": "internal/clip/point.go",
    "chars": 304,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipPoint(\n\tpoint *g"
  },
  {
    "path": "internal/clip/polygon.go",
    "chars": 992,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipPolygon(\n\tpolygo"
  },
  {
    "path": "internal/clip/rect.go",
    "chars": 462,
    "preview": "package clip\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nfunc clipRect(\n\trect *geo"
  },
  {
    "path": "internal/collection/collection.go",
    "chars": 14046,
    "preview": "package collection\n\nimport (\n\t\"math\"\n\t\"runtime\"\n\n\t\"github.com/tidwall/btree\"\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/"
  },
  {
    "path": "internal/collection/collection_test.go",
    "chars": 20248,
    "preview": "package collection\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tidwall/geojson\""
  },
  {
    "path": "internal/collection/geodesic.go",
    "chars": 3148,
    "preview": "package collection\n\nimport (\n\t\"math\"\n\n\t\"github.com/tidwall/tile38/internal/object\"\n)\n\nfunc geodeticDistAlgo(center [2]fl"
  },
  {
    "path": "internal/collection/string.go",
    "chars": 1262,
    "preview": "package collection\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n)\n\nt"
  },
  {
    "path": "internal/deadline/deadline.go",
    "chars": 781,
    "preview": "package deadline\n\nimport \"time\"\n\n// Deadline allows for commands to expire when they run too long\ntype Deadline struct {"
  },
  {
    "path": "internal/endpoint/amqp.go",
    "chars": 2726,
    "preview": "package endpoint\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/streadway/amqp\"\n)\n\nconst amqpExpiresAfter = time."
  },
  {
    "path": "internal/endpoint/cfqueue.go",
    "chars": 1812,
    "preview": "package endpoint\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/cloudflare/cloudflare-go/v4\"\n\t\"github.com/cloudflare"
  },
  {
    "path": "internal/endpoint/disque.go",
    "chars": 1662,
    "preview": "package endpoint\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/redis\"\n\t\"github.com/tidwall/tile38/inter"
  },
  {
    "path": "internal/endpoint/endpoint.go",
    "chars": 20514,
    "preview": "package endpoint\n\nimport (\n\t\"errors\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/strea"
  },
  {
    "path": "internal/endpoint/eventHub.go",
    "chars": 1137,
    "preview": "package endpoint\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\teventhub \"github.com/Azure/azure-eve"
  },
  {
    "path": "internal/endpoint/grpc.go",
    "chars": 1659,
    "preview": "package endpoint\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/tile38/internal/hservice\"\n\t\"golang.org"
  },
  {
    "path": "internal/endpoint/http.go",
    "chars": 1483,
    "preview": "package endpoint\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"time\"\n)\n\nconst (\n\thttpExpiresAfter       = time.Second * "
  },
  {
    "path": "internal/endpoint/kafka.go",
    "chars": 5513,
    "preview": "package endpoint\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\tlg \"log\"\n\n\t\"github.com/"
  },
  {
    "path": "internal/endpoint/local.go",
    "chars": 741,
    "preview": "package endpoint\n\n// LocalPublisher is used to publish local notifications\ntype LocalPublisher interface {\n\tPublish(chan"
  },
  {
    "path": "internal/endpoint/mqtt.go",
    "chars": 2758,
    "preview": "package endpoint\n\nimport (\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\tpaho \"github.com/ecl"
  },
  {
    "path": "internal/endpoint/nats.go",
    "chars": 2775,
    "preview": "package endpoint\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/nats-io/nats.go\"\n\t\"github.com/nats-io/nats.go"
  },
  {
    "path": "internal/endpoint/pubsub.go",
    "chars": 1776,
    "preview": "package endpoint\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"cloud.google.com/go/pubsub\"\n\t\"google.golang.org/api/opti"
  },
  {
    "path": "internal/endpoint/redis.go",
    "chars": 1399,
    "preview": "package endpoint\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/redis\"\n)\n\nconst redisExpiresAfter = time"
  },
  {
    "path": "internal/endpoint/scram_client.go",
    "chars": 763,
    "preview": "package endpoint\n\nimport (\n\t\"crypto/sha256\"\n\t\"crypto/sha512\"\n\n\t\"github.com/xdg-go/scram\"\n)\n\nvar (\n\tSHA256 scram.HashGene"
  },
  {
    "path": "internal/endpoint/sqs.go",
    "chars": 3534,
    "preview": "package endpoint\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"github.com/aws/aws-sdk-go/a"
  },
  {
    "path": "internal/field/field.go",
    "chars": 5024,
    "preview": "package field\n\nimport (\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tidwall/pretty\"\n)\n\nvar Z"
  },
  {
    "path": "internal/field/field_test.go",
    "chars": 5739,
    "preview": "package field\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tidwall/assert\"\n)\n\nfunc mLT(a, b Value) bool  { return a.Less(b) }\nfunc"
  },
  {
    "path": "internal/field/list_binary.go",
    "chars": 7724,
    "preview": "package field\n\nimport (\n\t\"encoding/binary\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tid"
  },
  {
    "path": "internal/field/list_struct.go",
    "chars": 1798,
    "preview": "//go:build exclude\n\npackage field\n\ntype List struct {\n\tentries []Field\n}\n\n// bsearch searches array for value.\nfunc (fie"
  },
  {
    "path": "internal/field/list_test.go",
    "chars": 5701,
    "preview": "package field\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tidwall/assert\"\n\t\"github.com/tidwall/btree\""
  },
  {
    "path": "internal/glob/glob.go",
    "chars": 1935,
    "preview": "package glob\n\nimport \"strings\"\n\n// Glob structure for simple string matching\ntype Glob struct {\n\tPattern string\n\tDesc   "
  },
  {
    "path": "internal/glob/glob_test.go",
    "chars": 10169,
    "preview": "package glob\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc test(t *testing.T, pattern string, desc bool, limitsExpec"
  },
  {
    "path": "internal/glob/match.go",
    "chars": 4942,
    "preview": "// Copyright 2010 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license "
  },
  {
    "path": "internal/hservice/gen.sh",
    "chars": 107,
    "preview": "#!/bin/bash\n\ncd $(dirname \"${BASH_SOURCE[0]}\")\nprotoc --go_out=plugins=grpc,import_path=hservice:. *.proto\n"
  },
  {
    "path": "internal/hservice/hservice.pb.go",
    "chars": 5268,
    "preview": "// Code generated by protoc-gen-go.\n// source: hservice.proto\n// DO NOT EDIT!\n\n/*\nPackage hservice is a generated protoc"
  },
  {
    "path": "internal/hservice/hservice.proto",
    "chars": 504,
    "preview": "syntax = \"proto3\";\n\noption java_multiple_files = true;\noption java_package = \"com.tile38.hservice\";\noption java_outer_cl"
  },
  {
    "path": "internal/log/log.go",
    "chars": 4783,
    "preview": "package log\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"go.uber.org/zap\"\n\t\"golang.or"
  },
  {
    "path": "internal/log/log_test.go",
    "chars": 4290,
    "preview": "package log\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n\t\"go.uber.org/"
  },
  {
    "path": "internal/object/object_binary.go",
    "chars": 3147,
    "preview": "package object\n\nimport (\n\t\"encoding/binary\"\n\t\"unsafe\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geomet"
  },
  {
    "path": "internal/object/object_struct.go",
    "chars": 1394,
    "preview": "//go:build exclude\n\npackage object\n\nimport (\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n\t\"gith"
  },
  {
    "path": "internal/object/object_test.go",
    "chars": 399,
    "preview": "package object\n\nimport (\n\t\"testing\"\n\n\t\"github.com/tidwall/assert\"\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geo"
  },
  {
    "path": "internal/server/aof.go",
    "chars": 11744,
    "preview": "package server\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"net\"\n\t\"os\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"gi"
  },
  {
    "path": "internal/server/aofmigrate.go",
    "chars": 3497,
    "preview": "package server\n\nimport (\n\t\"bufio\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"path\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t"
  },
  {
    "path": "internal/server/aofshrink.go",
    "chars": 8081,
    "preview": "package server\n\nimport (\n\t\"math\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/btree\"\n\t\"github.com/tidwall/t"
  },
  {
    "path": "internal/server/bson.go",
    "chars": 770,
    "preview": "package server\n\nimport (\n\t\"crypto/md5\"\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n"
  },
  {
    "path": "internal/server/bson_test.go",
    "chars": 116,
    "preview": "package server\n\nimport \"testing\"\n\nfunc TestBSON(t *testing.T) {\n\tid := bsonID()\n\tif len(id) != 24 {\n\t\tt.Fail()\n\t}\n}\n"
  },
  {
    "path": "internal/server/checksum.go",
    "chars": 5230,
    "preview": "package server\n\nimport (\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"github.com/tid"
  },
  {
    "path": "internal/server/client.go",
    "chars": 5566,
    "preview": "package server\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n)\n"
  },
  {
    "path": "internal/server/config.go",
    "chars": 14113,
    "preview": "package server\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\t\"git"
  },
  {
    "path": "internal/server/crud.go",
    "chars": 26598,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mmcloughlin/geohash\"\n\t\"github.com/"
  },
  {
    "path": "internal/server/dev.go",
    "chars": 4326,
    "preview": "package server\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"g"
  },
  {
    "path": "internal/server/expire.go",
    "chars": 1856,
    "preview": "package server\n\nimport (\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/tile38/internal/collection\"\n\t\"github.com/tidwall/tile38/i"
  },
  {
    "path": "internal/server/expr.go",
    "chars": 4296,
    "preview": "package server\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/tidwall/expr\"\n\t\"github.com/tidwall/geojson\"\n\t\"github.com"
  },
  {
    "path": "internal/server/expression.go",
    "chars": 4483,
    "preview": "package server\n\nimport (\n\t\"strings\"\n\n\t\"github.com/tidwall/geojson\"\n)\n\n// BinaryOp represents various operators for expre"
  },
  {
    "path": "internal/server/fence.go",
    "chars": 12309,
    "preview": "package server\n\nimport (\n\t\"math\"\n\t\"sort\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/"
  },
  {
    "path": "internal/server/follow.go",
    "chars": 8698,
    "preview": "package server\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"github.com/t"
  },
  {
    "path": "internal/server/group.go",
    "chars": 3263,
    "preview": "package server\n\nimport (\n\t\"github.com/tidwall/btree\"\n)\n\nfunc byGroupHook(va, vb interface{}) bool {\n\ta, b := va.(*groupI"
  },
  {
    "path": "internal/server/hooks.go",
    "chars": 16837,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/t"
  },
  {
    "path": "internal/server/json.go",
    "chars": 8041,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github"
  },
  {
    "path": "internal/server/json_test.go",
    "chars": 875,
    "preview": "package server\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\nfunc BenchmarkJSONString(t *testing.B) {\n\tvar s = \"the need for "
  },
  {
    "path": "internal/server/keys.go",
    "chars": 1332,
    "preview": "package server\n\nimport (\n\t\"encoding/json\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"github.com/tidwall/tile38/internal/colle"
  },
  {
    "path": "internal/server/live.go",
    "chars": 4563,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/redcon\"\n\t\"github.c"
  },
  {
    "path": "internal/server/metrics.go",
    "chars": 6148,
    "preview": "package server\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/tidwall/tile38/core\"\n\t\"github.com/tidwall/tile38/internal/coll"
  },
  {
    "path": "internal/server/monitor.go",
    "chars": 2143,
    "preview": "package server\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n)\n\ntype liveMonit"
  },
  {
    "path": "internal/server/must.go",
    "chars": 186,
    "preview": "package server\n\nfunc Must[T any](a T, err error) T {\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\treturn a\n}\n\nfunc Default[T compar"
  },
  {
    "path": "internal/server/must_test.go",
    "chars": 482,
    "preview": "package server\n\nimport (\n\t\"errors\"\n\t\"testing\"\n)\n\nfunc TestMust(t *testing.T) {\n\tif Must(1, nil) != 1 {\n\t\tt.Fail()\n\t}\n\tfu"
  },
  {
    "path": "internal/server/mvt.go",
    "chars": 3422,
    "preview": "package server\n\nimport (\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n\t\"g"
  },
  {
    "path": "internal/server/mvt_test.go",
    "chars": 1865,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidwall/geojson/geometry\"\n\t\"git"
  },
  {
    "path": "internal/server/output.go",
    "chars": 823,
    "preview": "package server\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n)\n\n// OUTPUT [resp|json]\nfunc (s *Server) cmdOUT"
  },
  {
    "path": "internal/server/pubqueue.go",
    "chars": 1627,
    "preview": "package server\n\nimport (\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/tidwall/redcon\"\n)\n\ntype pubQueue struct {\n\tcond    *sync.Cond\n\tent"
  },
  {
    "path": "internal/server/pubsub.go",
    "chars": 9032,
    "preview": "package server\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\t\"github.com/tidwall/match"
  },
  {
    "path": "internal/server/readonly.go",
    "chars": 790,
    "preview": "package server\n\nimport (\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"github.com/tidwall/tile38/internal/log\"\n)\n\n// READONLY ye"
  },
  {
    "path": "internal/server/respconn.go",
    "chars": 954,
    "preview": "package server\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n)\n\n// RESPConn represents a simple resp connection.\n"
  },
  {
    "path": "internal/server/scan.go",
    "chars": 2359,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"time\"\n\n\t\"github.com/tidwall/resp\"\n\t\"github.com/tidwall/tile38/internal/object\"\n)\n\nfu"
  },
  {
    "path": "internal/server/scanner.go",
    "chars": 12602,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/mmcloughlin/g"
  },
  {
    "path": "internal/server/scanner_test.go",
    "chars": 1428,
    "preview": "package server\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tidwall/geojson\"\n\t\"github.com/tidw"
  },
  {
    "path": "internal/server/scripts.go",
    "chars": 23509,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\""
  },
  {
    "path": "internal/server/search.go",
    "chars": 19743,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/iwpnd/sectr\"\n\t\"github.com"
  },
  {
    "path": "internal/server/server.go",
    "chars": 48111,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/sha1\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"errors\"\n\t\"fmt\"\n\t"
  },
  {
    "path": "internal/server/stats.go",
    "chars": 20193,
    "preview": "package server\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"syn"
  },
  {
    "path": "internal/server/stats_cpu.go",
    "chars": 297,
    "preview": "//go:build !linux && !darwin\n\npackage server\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n)\n\nfunc (s *Server) writeInfoCPU(w *bytes.Buffer)"
  },
  {
    "path": "internal/server/stats_cpu_darlin.go",
    "chars": 678,
    "preview": "//go:build linux || darwin\n\npackage server\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"syscall\"\n)\n\nfunc (s *Server) writeInfoCPU(w *byte"
  },
  {
    "path": "internal/server/test.go",
    "chars": 9613,
    "preview": "package server\n\n// TEST command: spatial tests without walking the tree.\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\""
  },
  {
    "path": "internal/server/token.go",
    "chars": 19853,
    "preview": "package server\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/tidwall/tile38/internal/field\"\n\t\"g"
  },
  {
    "path": "internal/server/token_test.go",
    "chars": 4415,
    "preview": "package server\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/tidwall/tile38/internal/field\"\n)\n\nfunc TestLowerCompare(t *"
  },
  {
    "path": "internal/sstring/sstring.go",
    "chars": 1020,
    "preview": "// Package shared allows for\npackage sstring\n\nimport (\n\t\"sync\"\n\t\"unsafe\"\n\n\t\"github.com/tidwall/hashmap\"\n)\n\nvar mu sync.M"
  },
  {
    "path": "internal/sstring/sstring_test.go",
    "chars": 1631,
    "preview": "package sstring\n\nimport (\n\t\"math/rand\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/tidwall/assert\"\n)\n\nfunc TestShared(t *testing.T)"
  },
  {
    "path": "internal/viewer/index.html",
    "chars": 3476,
    "preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<title>Tile38 Map Viewer</title>\n<meta name=\"viewport\" "
  },
  {
    "path": "internal/viewer/viewer.go",
    "chars": 1860,
    "preview": "package viewer\n\nimport (\n\t\"bytes\"\n\t\"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n//go:em"
  },
  {
    "path": "scripts/RELEASE.md",
    "chars": 318,
    "preview": "**To bump a new release of Tile38**\n\n- Update CHANGELOG.md to include the newest changes.\n- `git commit -m $vers` change"
  },
  {
    "path": "scripts/build.sh",
    "chars": 1052,
    "preview": "#!/bin/bash\n\nset -e\ncd $(dirname \"${BASH_SOURCE[0]}\")/..\n\nif [ \"$1\" == \"\" ]; then\n\techo \"error: missing argument (binary"
  },
  {
    "path": "scripts/docker-push.sh",
    "chars": 1784,
    "preview": "#!/bin/bash\n\nset -e\ncd $(dirname \"${BASH_SOURCE[0]}\")/..\n\n# GIT_BRANCH is the current branch name\nexport GIT_BRANCH=$(gi"
  },
  {
    "path": "scripts/package.sh",
    "chars": 973,
    "preview": "#!/bin/bash\n\nset -e\ncd $(dirname \"${BASH_SOURCE[0]}\")/..\n\nPLATFORM=\"$1\"\nGOOS=\"$2\"\nGOARCH=\"$3\"\nVERSION=$(git describe --t"
  },
  {
    "path": "scripts/test.sh",
    "chars": 470,
    "preview": "#!/bin/bash\n\nset -e\ncd $(dirname \"${BASH_SOURCE[0]}\")/..\n\nexport CGO_ENABLED=0\n\ncd tests\ngo test -coverpkg=../internal/s"
  },
  {
    "path": "tests/107/.gitignore",
    "chars": 25,
    "preview": "appendonly.aof\nlog\ndata/\n"
  },
  {
    "path": "tests/107/LINK",
    "chars": 45,
    "preview": "https://github.com/tidwall/tile38/issues/107\n"
  },
  {
    "path": "tests/107/main.go",
    "chars": 8845,
    "preview": "package main\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"math/rand\"\n\t\"net/http\"\n\t\"os\"\n\t"
  },
  {
    "path": "tests/616/main.go",
    "chars": 3307,
    "preview": "// Test Tile38 for Expiration Drift\n// Issue #616\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github."
  },
  {
    "path": "tests/README.md",
    "chars": 844,
    "preview": "## Tile38 Integration Testing\n\n- Uses Redis protocol\n- The Tile38 data is flushed before every `DoBatch`\n\nA basic test o"
  },
  {
    "path": "tests/aof_test.go",
    "chars": 8183,
    "preview": "package tests\n\nimport (\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http\"\n\t\""
  },
  {
    "path": "tests/client_test.go",
    "chars": 4530,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gomodule/redigo/redis\"\n\t\"github.com/tidwall/gjson\"\n\t\"g"
  },
  {
    "path": "tests/fence_roaming_test.go",
    "chars": 8249,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/redi"
  },
  {
    "path": "tests/fence_test.go",
    "chars": 13213,
    "preview": "package tests\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"s"
  },
  {
    "path": "tests/follower_test.go",
    "chars": 1966,
    "preview": "package tests\n\nimport \"time\"\n\nfunc subTestFollower(g *testGroup) {\n\tg.regSubTest(\"follow\", follower_follow_test)\n}\n\nfunc"
  },
  {
    "path": "tests/json_test.go",
    "chars": 2692,
    "preview": "package tests\n\nfunc subTestJSON(g *testGroup) {\n\tg.regSubTest(\"basic\", json_JSET_basic_test)\n\tg.regSubTest(\"geojson\", js"
  },
  {
    "path": "tests/keys_search_test.go",
    "chars": 57534,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"sort\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/r"
  },
  {
    "path": "tests/keys_test.go",
    "chars": 47634,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/redis\"\n\t\"github.c"
  },
  {
    "path": "tests/metrics_test.go",
    "chars": 1793,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n)\n\nfunc subTestMetrics(g *testGroup) {\n\tg.regSubTest(\"basic\""
  },
  {
    "path": "tests/mock_io_test.go",
    "chars": 2899,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjso"
  },
  {
    "path": "tests/mock_test.go",
    "chars": 8177,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"ti"
  },
  {
    "path": "tests/monitor_test.go",
    "chars": 1413,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/gomodule/redigo/redis\"\n)\n\nfunc subTestMonitor(g *testGro"
  },
  {
    "path": "tests/proto_test.go",
    "chars": 1701,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n)\n\nfunc subTestProto(g *testGroup) {\n\tg.regSubTest(\"HTTP CORS\", proto_HTTP_CO"
  },
  {
    "path": "tests/scripts_test.go",
    "chars": 3330,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nfunc subTestScripts(g *testGroup) {\n\tg.regSubTest(\"BASIC\", scripts_BASIC_te"
  },
  {
    "path": "tests/stats_test.go",
    "chars": 665,
    "preview": "package tests\n\nimport (\n\t\"errors\"\n\n\t\"github.com/tidwall/gjson\"\n)\n\nfunc subTestInfo(g *testGroup) {\n\tg.regSubTest(\"valid "
  },
  {
    "path": "tests/testcmd_test.go",
    "chars": 23651,
    "preview": "package tests\n\nfunc subTestTestCmd(g *testGroup) {\n\tg.regSubTest(\"WITHIN\", testcmd_WITHIN_test)\n\tg.regSubTest(\"INTERSECT"
  },
  {
    "path": "tests/tests_test.go",
    "chars": 6725,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"os\"\n\t\"os/signal\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"testing\"\n\t\"tim"
  },
  {
    "path": "tests/timeout_test.go",
    "chars": 5133,
    "preview": "package tests\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gomodule/redigo/redis\"\n)\n\nfunc subTestTimeo"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the tidwall/tile38 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 152 files (1.0 MB), approximately 352.9k tokens, and a symbol index with 1191 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!