Full Code of nat/keyrace for AI

main 8c4f3d38e2c9 cached
198 files
1.1 MB
280.8k tokens
19 symbols
1 requests
Download .txt
Showing preview only (1,175K chars total). Download the full file or copy to clipboard to get everything.
Repository: nat/keyrace
Branch: main
Commit: 8c4f3d38e2c9
Files: 198
Total size: 1.1 MB

Directory structure:
gitextract_yvxi4i9t/

├── .github/
│   └── workflows/
│       ├── build_app.yml
│       └── make-test.yml
├── .gitignore
├── Makefile
├── README.md
├── go.mod
├── go.sum
├── keyrace.c
├── mac/
│   ├── Podfile
│   ├── Pods/
│   │   ├── Charts/
│   │   │   ├── LICENSE
│   │   │   ├── README.md
│   │   │   └── Source/
│   │   │       └── Charts/
│   │   │           ├── Animation/
│   │   │           │   ├── Animator.swift
│   │   │           │   └── ChartAnimationEasing.swift
│   │   │           ├── Charts/
│   │   │           │   ├── BarChartView.swift
│   │   │           │   ├── BarLineChartViewBase.swift
│   │   │           │   ├── BubbleChartView.swift
│   │   │           │   ├── CandleStickChartView.swift
│   │   │           │   ├── ChartViewBase.swift
│   │   │           │   ├── CombinedChartView.swift
│   │   │           │   ├── HorizontalBarChartView.swift
│   │   │           │   ├── LineChartView.swift
│   │   │           │   ├── PieChartView.swift
│   │   │           │   ├── PieRadarChartViewBase.swift
│   │   │           │   ├── RadarChartView.swift
│   │   │           │   └── ScatterChartView.swift
│   │   │           ├── Components/
│   │   │           │   ├── AxisBase.swift
│   │   │           │   ├── ChartLimitLine.swift
│   │   │           │   ├── ComponentBase.swift
│   │   │           │   ├── Description.swift
│   │   │           │   ├── IMarker.swift
│   │   │           │   ├── Legend.swift
│   │   │           │   ├── LegendEntry.swift
│   │   │           │   ├── MarkerImage.swift
│   │   │           │   ├── MarkerView.swift
│   │   │           │   ├── XAxis.swift
│   │   │           │   └── YAxis.swift
│   │   │           ├── Data/
│   │   │           │   ├── Implementations/
│   │   │           │   │   ├── ChartBaseDataSet.swift
│   │   │           │   │   └── Standard/
│   │   │           │   │       ├── BarChartData.swift
│   │   │           │   │       ├── BarChartDataEntry.swift
│   │   │           │   │       ├── BarChartDataSet.swift
│   │   │           │   │       ├── BarLineScatterCandleBubbleChartData.swift
│   │   │           │   │       ├── BarLineScatterCandleBubbleChartDataSet.swift
│   │   │           │   │       ├── BubbleChartData.swift
│   │   │           │   │       ├── BubbleChartDataEntry.swift
│   │   │           │   │       ├── BubbleChartDataSet.swift
│   │   │           │   │       ├── CandleChartData.swift
│   │   │           │   │       ├── CandleChartDataEntry.swift
│   │   │           │   │       ├── CandleChartDataSet.swift
│   │   │           │   │       ├── ChartData.swift
│   │   │           │   │       ├── ChartDataEntry.swift
│   │   │           │   │       ├── ChartDataEntryBase.swift
│   │   │           │   │       ├── ChartDataSet.swift
│   │   │           │   │       ├── CombinedChartData.swift
│   │   │           │   │       ├── LineChartData.swift
│   │   │           │   │       ├── LineChartDataSet.swift
│   │   │           │   │       ├── LineRadarChartDataSet.swift
│   │   │           │   │       ├── LineScatterCandleRadarChartDataSet.swift
│   │   │           │   │       ├── PieChartData.swift
│   │   │           │   │       ├── PieChartDataEntry.swift
│   │   │           │   │       ├── PieChartDataSet.swift
│   │   │           │   │       ├── RadarChartData.swift
│   │   │           │   │       ├── RadarChartDataEntry.swift
│   │   │           │   │       ├── RadarChartDataSet.swift
│   │   │           │   │       ├── ScatterChartData.swift
│   │   │           │   │       └── ScatterChartDataSet.swift
│   │   │           │   └── Interfaces/
│   │   │           │       ├── IBarChartDataSet.swift
│   │   │           │       ├── IBarLineScatterCandleBubbleChartDataSet.swift
│   │   │           │       ├── IBubbleChartDataSet.swift
│   │   │           │       ├── ICandleChartDataSet.swift
│   │   │           │       ├── IChartDataSet.swift
│   │   │           │       ├── ILineChartDataSet.swift
│   │   │           │       ├── ILineRadarChartDataSet.swift
│   │   │           │       ├── ILineScatterCandleRadarChartDataSet.swift
│   │   │           │       ├── IPieChartDataSet.swift
│   │   │           │       ├── IRadarChartDataSet.swift
│   │   │           │       └── IScatterChartDataSet.swift
│   │   │           ├── Filters/
│   │   │           │   ├── DataApproximator+N.swift
│   │   │           │   └── DataApproximator.swift
│   │   │           ├── Formatters/
│   │   │           │   ├── DefaultAxisValueFormatter.swift
│   │   │           │   ├── DefaultFillFormatter.swift
│   │   │           │   ├── DefaultValueFormatter.swift
│   │   │           │   ├── IAxisValueFormatter.swift
│   │   │           │   ├── IFillFormatter.swift
│   │   │           │   ├── IValueFormatter.swift
│   │   │           │   └── IndexAxisValueFormatter.swift
│   │   │           ├── Highlight/
│   │   │           │   ├── BarHighlighter.swift
│   │   │           │   ├── ChartHighlighter.swift
│   │   │           │   ├── CombinedHighlighter.swift
│   │   │           │   ├── Highlight.swift
│   │   │           │   ├── HorizontalBarHighlighter.swift
│   │   │           │   ├── IHighlighter.swift
│   │   │           │   ├── PieHighlighter.swift
│   │   │           │   ├── PieRadarHighlighter.swift
│   │   │           │   ├── RadarHighlighter.swift
│   │   │           │   └── Range.swift
│   │   │           ├── Interfaces/
│   │   │           │   ├── BarChartDataProvider.swift
│   │   │           │   ├── BarLineScatterCandleBubbleChartDataProvider.swift
│   │   │           │   ├── BubbleChartDataProvider.swift
│   │   │           │   ├── CandleChartDataProvider.swift
│   │   │           │   ├── ChartDataProvider.swift
│   │   │           │   ├── CombinedChartDataProvider.swift
│   │   │           │   ├── LineChartDataProvider.swift
│   │   │           │   └── ScatterChartDataProvider.swift
│   │   │           ├── Jobs/
│   │   │           │   ├── AnimatedMoveViewJob.swift
│   │   │           │   ├── AnimatedViewPortJob.swift
│   │   │           │   ├── AnimatedZoomViewJob.swift
│   │   │           │   ├── MoveViewJob.swift
│   │   │           │   ├── ViewPortJob.swift
│   │   │           │   └── ZoomViewJob.swift
│   │   │           ├── Renderers/
│   │   │           │   ├── AxisRendererBase.swift
│   │   │           │   ├── BarChartRenderer.swift
│   │   │           │   ├── BarLineScatterCandleBubbleRenderer.swift
│   │   │           │   ├── BubbleChartRenderer.swift
│   │   │           │   ├── CandleStickChartRenderer.swift
│   │   │           │   ├── ChartDataRendererBase.swift
│   │   │           │   ├── CombinedChartRenderer.swift
│   │   │           │   ├── HorizontalBarChartRenderer.swift
│   │   │           │   ├── LegendRenderer.swift
│   │   │           │   ├── LineChartRenderer.swift
│   │   │           │   ├── LineRadarRenderer.swift
│   │   │           │   ├── LineScatterCandleRadarRenderer.swift
│   │   │           │   ├── PieChartRenderer.swift
│   │   │           │   ├── RadarChartRenderer.swift
│   │   │           │   ├── Renderer.swift
│   │   │           │   ├── Scatter/
│   │   │           │   │   ├── ChevronDownShapeRenderer.swift
│   │   │           │   │   ├── ChevronUpShapeRenderer.swift
│   │   │           │   │   ├── CircleShapeRenderer.swift
│   │   │           │   │   ├── CrossShapeRenderer.swift
│   │   │           │   │   ├── IShapeRenderer.swift
│   │   │           │   │   ├── SquareShapeRenderer.swift
│   │   │           │   │   ├── TriangleShapeRenderer.swift
│   │   │           │   │   └── XShapeRenderer.swift
│   │   │           │   ├── ScatterChartRenderer.swift
│   │   │           │   ├── XAxisRenderer.swift
│   │   │           │   ├── XAxisRendererHorizontalBarChart.swift
│   │   │           │   ├── XAxisRendererRadarChart.swift
│   │   │           │   ├── YAxisRenderer.swift
│   │   │           │   ├── YAxisRendererHorizontalBarChart.swift
│   │   │           │   └── YAxisRendererRadarChart.swift
│   │   │           └── Utils/
│   │   │               ├── ChartColorTemplates.swift
│   │   │               ├── ChartUtils.swift
│   │   │               ├── Fill.swift
│   │   │               ├── Platform+Accessibility.swift
│   │   │               ├── Platform+Color.swift
│   │   │               ├── Platform+Gestures.swift
│   │   │               ├── Platform+Graphics.swift
│   │   │               ├── Platform+Touch Handling.swift
│   │   │               ├── Platform.swift
│   │   │               ├── Transformer.swift
│   │   │               ├── TransformerHorizontalBarChart.swift
│   │   │               └── ViewPortHandler.swift
│   │   ├── Pods.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           ├── Charts.xcscheme
│   │   │           └── Pods-keyrace-mac.xcscheme
│   │   └── Target Support Files/
│   │       ├── Charts/
│   │       │   ├── Charts-Info.plist
│   │       │   ├── Charts-dummy.m
│   │       │   ├── Charts-prefix.pch
│   │       │   ├── Charts-umbrella.h
│   │       │   ├── Charts.debug.xcconfig
│   │       │   ├── Charts.modulemap
│   │       │   └── Charts.release.xcconfig
│   │       └── Pods-keyrace-mac/
│   │           ├── Pods-keyrace-mac-Info.plist
│   │           ├── Pods-keyrace-mac-acknowledgements.markdown
│   │           ├── Pods-keyrace-mac-acknowledgements.plist
│   │           ├── Pods-keyrace-mac-dummy.m
│   │           ├── Pods-keyrace-mac-frameworks-Debug-input-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Debug-output-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Release-input-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Release-output-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks.sh
│   │           ├── Pods-keyrace-mac-umbrella.h
│   │           ├── Pods-keyrace-mac.debug.xcconfig
│   │           ├── Pods-keyrace-mac.modulemap
│   │           └── Pods-keyrace-mac.release.xcconfig
│   ├── keyrace-mac/
│   │   ├── AppDelegate.swift
│   │   ├── Assets.xcassets/
│   │   │   ├── AccentColor.colorset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   ├── Contents.json
│   │   │   └── magic-keyboard.imageset/
│   │   │       └── Contents.json
│   │   ├── ContentView.swift
│   │   ├── GitHub.swift
│   │   ├── Info.plist
│   │   ├── KeyTap.swift
│   │   ├── KeyboardView.swift
│   │   ├── LeaderboardView.swift
│   │   ├── MenuView.swift
│   │   ├── Preview Content/
│   │   │   └── Preview Assets.xcassets/
│   │   │       └── Contents.json
│   │   ├── SettingsView.swift
│   │   ├── TypingChart.swift
│   │   ├── UserDefaults.swift
│   │   └── keyrace_mac.entitlements
│   ├── keyrace-mac.xcodeproj/
│   │   ├── project.pbxproj
│   │   ├── project.xcworkspace/
│   │   │   ├── contents.xcworkspacedata
│   │   │   └── xcshareddata/
│   │   │       └── IDEWorkspaceChecks.plist
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── keyrace-mac.xcscheme
│   └── keyrace-mac.xcworkspace/
│       ├── contents.xcworkspacedata
│       └── xcshareddata/
│           └── IDEWorkspaceChecks.plist
└── server.go

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

================================================
FILE: .github/workflows/build_app.yml
================================================
name: build mac app

on: [push, pull_request]

jobs:
  build:
    runs-on: macOS-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v1
        with:
          fetch-depth: 0
      - name: Select Xcode 12.4
        run: sudo xcode-select -switch /Applications/Xcode_12.4.app
      - name: Build project
        run: make keyrace-mac
      - name: Save .zip as artifact
        uses: actions/upload-artifact@v1
        with:
          name: keyrace-mac.app
          path: ./build/mac


================================================
FILE: .github/workflows/make-test.yml
================================================
on: [push, pull_request]
name: make test
jobs:
  maketest:
    name: make test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: actions/setup-go@v2
        with:
          go-version: '^1.13.1' # The Go version to download (if necessary) and use.
      - name: make test
        run: make test
        shell: bash
        env:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}


================================================
FILE: .gitignore
================================================
# Xcode .gitignore
#
# Source:
# https://github.com/github/gitignore/blob/master/Global/Xcode.gitignore

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Gcc Patch
/*.gcno

## Sample Data
.assets/*.csv

## Secrets
Generated
Secrets.xcconfig

# Other
keyrace
keyrace.db
keyrace.dSYM
keyrace-server*
vendor


================================================
FILE: Makefile
================================================
SERVER=keyrace.app
BUILDTAGS=libsqlite3 sqlite_omit_load_extension

keyrace-server: $(wildcard *.go)
	go mod vendor || true
	go build -o $@ \
		-tags "$(BUILDTAGS)" $?

server: keyrace-server keyrace-server-linux ## Build the server.

keyrace-server-linux: $(wildcard *.go)
	# On a mac you need to `brew install sqlite`
	echo "Using sqlite broke the static binary building on macos"
	#go mod vendor
	#GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build \
	# -o $@ \
	# -tags "$(BUILDTAGS)" \
	# -installsuffix netgo -ldflags "-w -extldflags" $?

keyrace-mac:
	set -eo pipefail
	mkdir -p build/mac
	xcodebuild \
		-workspace mac/keyrace-mac.xcworkspace/ \
		-scheme keyrace-mac \
		-archivePath $(PWD)/build/keyrace.xcarchive \
		clean archive
	cp -r build/keyrace.xcarchive/Products/Applications/keyrace-mac.app build/mac

server-test: $(wildcard *.go)
	@echo "Running the go tests..."
	go mod vendor
	go test $?

test: server-test ## Run the tests.

deploy: keyrace-server-linux ## Deploy the server binary.
	scp keyrace-server-linux $(SERVER):

clean:
	rm -rf keyrace.dSYM

.PHONY: help
help: ## Show this help.
	@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'


================================================
FILE: README.md
================================================
# keyrace
Daily multiplayer keyboard races for macos

<img width="383" alt="image" src="https://user-images.githubusercontent.com/56260/108459319-47481a80-722b-11eb-89c5-7245d32aa64a.png">

## To install

```bash
git clone https://github.com/nat/keyrace.git
cd keyrace/mac
open keyrace-mac.xcworkspace
```

## To build and run

<kbd>Cmd (⌘)</kbd> + <kbd>R</kbd> or `Product` > `Run` in Xcode!

**NOTE:** If the `Run` option is grayed out in the menu, make sure that the correct scheme is selected: `Product` > `Scheme` > `keyrace-mac`. 


================================================
FILE: go.mod
================================================
module github.com/nat/keyrace

go 1.14

require (
	github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 // indirect
	github.com/improbable-eng/go-httpwares v0.0.0-20200609095714-edc8019f93cc
	github.com/karalabe/xgo v0.0.0-20191115072854-c5ccff8648a7 // indirect
	github.com/mattn/go-sqlite3 v1.14.6
	github.com/sirupsen/logrus v1.7.0
	golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
)


================================================
FILE: go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/TwinProduction/go-away v1.0.0 h1:C+l/Q6eC/epJu26V17zXgi3SDxrkGdSUq3kAyJHOlVU=
github.com/TwinProduction/go-away v1.0.0/go.mod h1:VB/lNzhkzh7Xw2QgU+tYBjMheldukJaIJzVaIx2rh30=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/improbable-eng/go-httpwares v0.0.0-20200609095714-edc8019f93cc h1:jPofYCdWojUaUhjlAe5yM/H4PFDfrZ6ldrlqoVv5YDM=
github.com/improbable-eng/go-httpwares v0.0.0-20200609095714-edc8019f93cc/go.mod h1:LE9Hs6fsYQ7RoDuFUQlYmlRAku9vUlSlO++jWNj+D0I=
github.com/karalabe/xgo v0.0.0-20191115072854-c5ccff8648a7 h1:AYzjK/SHz6m6mg5iuFwkrAhCc14jvCpW9d6frC9iDPE=
github.com/karalabe/xgo v0.0.0-20191115072854-c5ccff8648a7/go.mod h1:iYGcTYIPUvEWhFo6aKUuLchs+AV4ssYdyuBbQJZGcBk=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215 h1:0Uz5jLJQioKgVozXa1gzGbzYxbb/rhQEVvSWxzw5oUs=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=


================================================
FILE: keyrace.c
================================================
// NOTE: This client no longer works. Run the native mac client instead!
//
// gcc keyrace.c -o keyrace -framework ApplicationServices -framework Carbon -Wall -g
//
// To start tracking, run as: keyrace <username> <team>
// To print leaderboard, run: keyrace <team>
//
// Just use "default" as your team if you don't have one.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
#include <string.h>
#include <sys/stat.h>

const char KEYRACE_HOST[] = "159.89.136.69";
const char TMPFILE[] = "/tmp/keyrace.tmp";

char *username;
char *team;
int keycount = 0;
int last_day = -1;
int last_min = -1;

void update_savefile(int kc)
{
    FILE *f;
    f = fopen(TMPFILE, "w");
    fprintf(f, "%d\n", kc);
    fclose(f);
}

int load_savefile(void)
{
    struct stat stat_buffer;
    int saved_keycount;
    FILE *f;

    f = fopen(TMPFILE, "r");
    if (f == NULL)
        return 0;
    fscanf(f, "%d", &saved_keycount);

    if (stat(TMPFILE, &stat_buffer) != 0)
        return 0;

    struct tm mtime = *localtime(&stat_buffer.st_mtime);
    last_day = mtime.tm_yday;

    fclose(f);

    return saved_keycount;
}

void upload_count(char *name, int count)
{
    char s[1024];
    snprintf(s, 1024, "curl \"http://%s/count?team=%s&name=%s&count=%d\" 2> /dev/null > /dev/null", KEYRACE_HOST, team, name, count);
    system(s);
}

// invoked on every keypress
CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
    time_t t = time(NULL);

    if (type != kCGEventKeyDown && type != kCGEventFlagsChanged && type != kCGEventKeyUp)
    {
        return event;
    }

    struct tm tm = *localtime(&t);

    // Reset to 0 at midnight
    if (last_day != tm.tm_yday)
    {
        last_day = tm.tm_yday;
        keycount = 0;
    }

    keycount++;

    // Upload every minute
    if (last_min != tm.tm_min)
    {
        last_min = tm.tm_min;

        upload_count(username, keycount);
    }

    update_savefile(keycount);

    return event;
}

void strclean(char *src)
{
    char *p = src;
    while (*src)
    {
        if (isalnum(*src))
            *p++ = *src;
        src++;
    }
    *p = '\0';
}

void run_loop(void)
{
    // Create an event tap to retrieve keypresses.
    CGEventMask eventMask = (CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventFlagsChanged));
    CFMachPortRef eventTap = CGEventTapCreate(
        kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, CGEventCallback, NULL);

    // Exit the program if unable to create the event tap.
    if (!eventTap)
    {
        fprintf(stderr, "ERROR: Unable to create event tap.\n");
        exit(1);
    }

    // Create a run loop source and add enable the event tap.
    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
    CGEventTapEnable(eventTap, true);

    CFRunLoopRun();
}

int main(int argc, char **argv)
{

    if (argc < 2 || argc > 3 || !strcmp (argv[1], "--help"))
    {
        printf("Try: \n");
        printf("    %s <team> <username> -- to start logging\n", argv[0]);
        printf("    %s <team> -- to get the tracking\n", argv[0]);
        printf("Just use \"default\" as your team if you don't have one.\n");
        return 1;
    }

    if (argc == 2)
    {
        char cmd[1024];
        snprintf(cmd, 1024, "curl http://%s/?team=%s", KEYRACE_HOST, argv[1]);
        system(cmd);
        return 0;
    }

    username = argv[2];
    team = argv[1];
    strclean(username);
    strclean(team);

    keycount = load_savefile();

    printf("Starting counting keystrokes in the background.\n");

    int pid = fork();
    if (pid == 0)
    { // child
        setpgid(0, 0);
        run_loop();
    }
}

================================================
FILE: mac/Podfile
================================================
use_frameworks!
inhibit_all_warnings!

target 'keyrace-mac' do
	pod 'Charts'
end


================================================
FILE: mac/Pods/Charts/LICENSE
================================================
Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "{}"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2016-2019 Daniel Cohen Gindi & Philipp Jahoda

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



================================================
FILE: mac/Pods/Charts/README.md
================================================
**Version 3.5.0**, synced to [MPAndroidChart #f6a398b](https://github.com/PhilJay/MPAndroidChart/commit/f6a398b)

![alt tag](https://raw.github.com/danielgindi/Charts/master/Assets/feature_graphic.png)
  ![Supported Platforms](https://img.shields.io/cocoapods/p/Charts.svg) [![Releases](https://img.shields.io/github/release/danielgindi/Charts.svg)](https://github.com/danielgindi/Charts/releases) [![Latest pod release](https://img.shields.io/cocoapods/v/Charts.svg)](http://cocoapods.org/pods/charts) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/danielgindi/Charts.svg?branch=master)](https://travis-ci.org/danielgindi/Charts) [![codecov](https://codecov.io/gh/danielgindi/Charts/branch/master/graph/badge.svg)](https://codecov.io/gh/danielgindi/Charts)
[![Join the chat at https://gitter.im/danielgindi/Charts](https://badges.gitter.im/danielgindi/Charts.svg)](https://gitter.im/danielgindi/Charts?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

### Just a heads up: Charts 3.0 has some breaking changes. Please read [the release/migration notes](https://github.com/danielgindi/Charts/releases/tag/v3.0.0). 
### Another heads up: ChartsRealm is now in a [separate repo](https://github.com/danielgindi/ChartsRealm). Pods is also now `Charts` and `ChartsRealm`, instead of ~`Charts/Core`~ and ~`Charts/Realm`~
### One more heads up: As Swift evolves, if you are not using the latest Swift compiler, you shouldn't check out the master branch. Instead, you should go to the release page and pick up whatever suits you.

* Xcode 11 / Swift 5 (master branch)
* iOS >= 8.0 (Use as an **Embedded** Framework)
* tvOS >= 9.0
* macOS >= 10.11

Okay so there's this beautiful library called [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) by [Philipp Jahoda](https://www.linkedin.com/in/philippjahoda) which has become very popular amongst Android developers, but there was no decent solution to create charts for iOS.

I've chosen to write it in `Swift` as it can be highly optimized by the compiler, and can be used in both `Swift` and `ObjC` project. The demo project is written in `ObjC` to demonstrate how it works.

**An amazing feature** of this library now, for Android, iOS, tvOS and macOS, is the time it saves you when developing for both platforms, as the learning curve is singleton- it happens only once, and the code stays very similar so developers don't have to go around and re-invent the app to produce the same output with a different library. (And that's not even considering the fact that there's not really another good choice out there currently...)

## Having trouble running the demo?

* `ChartsDemo/ChartsDemo.xcodeproj` is the demo project for iOS/tvOS
* `ChartsDemo-OSX/ChartsDemo-OSX.xcodeproj` is the demo project for macOS
* Make sure you are running a supported version of Xcode.
  * Usually it is specified here a few lines above.
  * In most cases it will be the latest Xcode version.
* Make sure that your project supports Swift 5.0
* Optional: Run `carthage checkout` in the project folder, to fetch dependencies (i.e testing dependencies).
  * If you don't have Carthage - you can get it [here](https://github.com/Carthage/Carthage/releases).


## Usage

In order to correctly compile:

1. Drag the `Charts.xcodeproj` to your project  
2. Go to your target's settings, hit the "+" under the "Embedded Binaries" section, and select the Charts.framework  
3. `@import Charts`  
4.  When using Swift in an ObjC project:
   - You need to import your Bridging Header. Usually it is "*YourProject-Swift.h*", so in ChartsDemo it's "*ChartsDemo-Swift.h*". Do not try to actually include "*ChartsDemo-Swift.h*" in your project :-)
   - (Xcode 8.1 and earlier) Under "Build Options", mark "Embedded Content Contains Swift Code"
   - (Xcode 8.2+) Under "Build Options", mark "Always Embed Swift Standard Libraries"
5. When using [Realm.io](https://realm.io/):
   - Note that the Realm framework is not linked with Charts - it is only there for *optional* bindings. Which means that you need to have the framework in your project, and in a compatible version to whatever is compiled with Charts. We will do our best to always compile against the latest version.
   - You'll need to add `ChartsRealm` as a dependency too.

## 3rd party tutorials
#### Video tutorials

* [Chart in Swift - Setting Up a Basic Line Chart Using iOS Charts(Alex Nagy)](https://www.youtube.com/watch?v=mWhwe_tLNE8&list=PL_csAAO9PQ8bjzg-wxEff1Fr0Y5W1hrum&index=5)

#### Blog posts
* [Using Realm and Charts with Swift 3 in iOS 10 (Sami Korpela)](https://medium.com/@skoli/using-realm-and-charts-with-swift-3-in-ios-10-40c42e3838c0#.2gyymwfh8)
* [Creating a Line Chart in Swift 3 and iOS 10 (Osian Smith)](https://medium.com/@OsianSmith/creating-a-line-chart-in-swift-3-and-ios-10-2f647c95392e)
* [Beginning Set-up and Example Using Charts with Swift 3](https://github.com/annalizhaz/ChartsForSwiftBasic)
* [Creating a Radar Chart in Swift (David Piper)](https://medium.com/@HeyDaveTheDev/creating-a-radar-chart-in-swift-5791afcf92f0)
* [Plotting in IOS using Charts framework with SwiftUI (Evgeny Basisty)](https://medium.com/@zzzzbh/plotting-in-ios-using-charts-framework-with-swiftui-222034a2bea6)

Want your tutorial to show here? Create a PR!

## Troubleshooting

#### Can't compile?

* Please note the difference between installing a compiled framework from CocoaPods or Carthage, and copying the source code.
* Please read the **Usage** section again.
* Search in the issues
* Try to politely ask in the issues section

#### Other problems / feature requests

* Search in the issues
* Try to politely ask in the issues section

## CocoaPods Install

Add `pod 'Charts'` to your Podfile. "Charts" is the name of the library.  
For [Realm](https://realm.io/) support, please add `pod 'ChartsRealm'` too.

**Note:** ~~`pod 'ios-charts'`~~ is not the correct library, and refers to a different project by someone else.

## Carthage Install

Charts now include Carthage prebuilt binaries.

```carthage
github "danielgindi/Charts" == 3.5.0
github "danielgindi/Charts" ~> 3.5.0
```

In order to build the binaries for a new release, use `carthage build --no-skip-current && carthage archive Charts`.

## 3rd party bindings

Xamarin (by @Flash3001): *iOS* - [GitHub](https://github.com/Flash3001/iOSCharts.Xamarin)/[NuGet](https://www.nuget.org/packages/iOSCharts/). *Android* - [GitHub](https://github.com/Flash3001/MPAndroidChart.Xamarin)/[NuGet](https://www.nuget.org/packages/MPAndroidChart/).

## Help

If you like what you see here, and want to support the work being done in this repository, you could:
* Contribute code, issues and pull requests
* Let people know this library exists (:fire: spread the word :fire:)
* [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=68UL6Y8KUPS96) (You can buy me a beer, or you can buy me dinner :-)

**Note:** The author of [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) is the reason that this library exists, and is accepting [donations](https://github.com/PhilJay/MPAndroidChart#donations) on his page. He deserves them!

Questions & Issues
-----

If you are having questions or problems, you should:

 - Make sure you are using the latest version of the library. Check the [**release-section**](https://github.com/danielgindi/Charts/releases).
 - Study the Android version's [**Documentation-Wiki**](https://github.com/PhilJay/MPAndroidChart/wiki)
 - Study the (Still incomplete [![Doc-Percent](https://img.shields.io/cocoapods/metrics/doc-percent/Charts.svg)](http://cocoadocs.org/docsets/Charts/)) [**Pod-Documentation**](http://cocoadocs.org/docsets/Charts/)
 - Search or open questions on [**stackoverflow**](http://stackoverflow.com/questions/tagged/ios-charts) with the `ios-charts` tag
 - Search [**known issues**](https://github.com/danielgindi/Charts/issues) for your problem (open and closed)
 - Create new issues (please :fire: **search known issues before** :fire:, do not create duplicate issues)


Features
=======

**Core features:**
 - 8 different chart types
 - Scaling on both axes (with touch-gesture, axes separately or pinch-zoom)
 - Dragging / Panning (with touch-gesture)
 - Combined-Charts (line-, bar-, scatter-, candle-stick-, bubble-)
 - Dual (separate) Axes
 - Customizable Axes (both x- and y-axis)
 - Highlighting values (with customizable popup-views)
 - Save chart to camera-roll / export to PNG/JPEG
 - Predefined color templates
 - Legends (generated automatically, customizable)
 - Animations (build up animations, on both x- and y-axis)
 - Limit lines (providing additional information, maximums, ...)
 - Fully customizable (paints, typefaces, legends, colors, background, gestures, dashed lines, ...)
 - Plotting data directly from [**Realm.io**](https://realm.io) mobile database ([here](https://github.com/danielgindi/ChartsRealm))

**Chart types:**

*Screenshots are currently taken from the original repository, as they render exactly the same :-)*


 - **LineChart (with legend, simple design)**
![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart4.png)
 - **LineChart (with legend, simple design)**
![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_linechart3.png)

 - **LineChart (cubic lines)**
![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/cubiclinechart.png)

 - **LineChart (gradient fill)**
![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/line_chart_gradient.png)

 - **Combined-Chart (bar- and linechart in this case)**
![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/combined_chart.png)

 - **BarChart (with legend, simple design)**

![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/simpledesign_barchart3.png)

 - **BarChart (grouped DataSets)**

![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/groupedbarchart.png)

 - **Horizontal-BarChart**

![alt tag](https://raw.github.com/PhilJay/MPChart/master/screenshots/horizontal_barchart.png)


 - **PieChart (with selection, ...)**

![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/simpledesign_piechart1.png)

 - **ScatterChart** (with squares, triangles, circles, ... and more)

![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/scatterchart.png)

 - **CandleStickChart** (for financial data)

![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/candlestickchart.png)

 - **BubbleChart** (area covered by bubbles indicates the value)

![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/bubblechart.png)

 - **RadarChart** (spider web chart)

![alt tag](https://raw.github.com/PhilJay/MPAndroidChart/master/screenshots/radarchart.png)


Documentation
=======
Currently there's no need for documentation for the iOS/tvOS/macOS version, as the API is **95% the same** as on Android.  
You can read the official [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) documentation here: [**Wiki**](https://github.com/PhilJay/MPAndroidChart/wiki)

Or you can see the Charts Demo project in both Objective-C and Swift ([**ChartsDemo-iOS**](https://github.com/danielgindi/Charts/tree/master/ChartsDemo-iOS), as well as macOS [**ChartsDemo-macOS**](https://github.com/danielgindi/Charts/tree/master/ChartsDemo-macOS)) and learn the how-tos from it.


Special Thanks
=======

Goes to [@liuxuan30](https://github.com/liuxuan30), [@petester42](https://github.com/petester42) and  [@AlBirdie](https://github.com/AlBirdie) for new features, bugfixes, and lots and lots of involvement in our open-sourced community! You guys are a huge help to all of those coming here with questions and issues, and I couldn't respond to all of those without you.

### Our amazing sponsors

[Debricked](https://debricked.com/): Use open source securely

[![debricked](https://user-images.githubusercontent.com/4375169/73585544-25bfa800-44dd-11ea-9661-82519a125302.jpg)](https://debricked.com/)


License
=======
Copyright 2016 Daniel Cohen Gindi & Philipp Jahoda

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: mac/Pods/Charts/Source/Charts/Animation/Animator.swift
================================================
//
//  Animator.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics
import QuartzCore

@objc(ChartAnimatorDelegate)
public protocol AnimatorDelegate
{
    /// Called when the Animator has stepped.
    func animatorUpdated(_ animator: Animator)
    
    /// Called when the Animator has stopped.
    func animatorStopped(_ animator: Animator)
}

@objc(ChartAnimator)
open class Animator: NSObject
{
    @objc open weak var delegate: AnimatorDelegate?
    @objc open var updateBlock: (() -> Void)?
    @objc open var stopBlock: (() -> Void)?
    
    /// the phase that is animated and influences the drawn values on the x-axis
    @objc open var phaseX: Double = 1.0
    
    /// the phase that is animated and influences the drawn values on the y-axis
    @objc open var phaseY: Double = 1.0
    
    private var _startTimeX: TimeInterval = 0.0
    private var _startTimeY: TimeInterval = 0.0
    private var _displayLink: NSUIDisplayLink?
    
    private var _durationX: TimeInterval = 0.0
    private var _durationY: TimeInterval = 0.0
    
    private var _endTimeX: TimeInterval = 0.0
    private var _endTimeY: TimeInterval = 0.0
    private var _endTime: TimeInterval = 0.0
    
    private var _enabledX: Bool = false
    private var _enabledY: Bool = false
    
    private var _easingX: ChartEasingFunctionBlock?
    private var _easingY: ChartEasingFunctionBlock?

    public override init()
    {
        super.init()
    }
    
    deinit
    {
        stop()
    }
    
    @objc open func stop()
    {
        guard _displayLink != nil else { return }

        _displayLink?.remove(from: .main, forMode: RunLoop.Mode.common)
        _displayLink = nil

        _enabledX = false
        _enabledY = false

        // If we stopped an animation in the middle, we do not want to leave it like this
        if phaseX != 1.0 || phaseY != 1.0
        {
            phaseX = 1.0
            phaseY = 1.0

            delegate?.animatorUpdated(self)
            updateBlock?()
        }

        delegate?.animatorStopped(self)
        stopBlock?()
    }
    
    private func updateAnimationPhases(_ currentTime: TimeInterval)
    {
        if _enabledX
        {
            let elapsedTime: TimeInterval = currentTime - _startTimeX
            let duration: TimeInterval = _durationX
            var elapsed: TimeInterval = elapsedTime
            if elapsed > duration
            {
                elapsed = duration
            }
           
            phaseX = _easingX?(elapsed, duration) ?? elapsed / duration
        }
        
        if _enabledY
        {
            let elapsedTime: TimeInterval = currentTime - _startTimeY
            let duration: TimeInterval = _durationY
            var elapsed: TimeInterval = elapsedTime
            if elapsed > duration
            {
                elapsed = duration
            }

            phaseY = _easingY?(elapsed, duration) ?? elapsed / duration
        }
    }
    
    @objc private func animationLoop()
    {
        let currentTime: TimeInterval = CACurrentMediaTime()
        
        updateAnimationPhases(currentTime)

        delegate?.animatorUpdated(self)
        updateBlock?()
        
        if currentTime >= _endTime
        {
            stop()
        }
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingX: an easing function for the animation on the x axis
    ///   - easingY: an easing function for the animation on the y axis
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
    {
        stop()
        
        _startTimeX = CACurrentMediaTime()
        _startTimeY = _startTimeX
        _durationX = xAxisDuration
        _durationY = yAxisDuration
        _endTimeX = _startTimeX + xAxisDuration
        _endTimeY = _startTimeY + yAxisDuration
        _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
        _enabledX = xAxisDuration > 0.0
        _enabledY = yAxisDuration > 0.0
        
        _easingX = easingX
        _easingY = easingY
        
        // Take care of the first frame if rendering is already scheduled...
        updateAnimationPhases(_startTimeX)
        
        if _enabledX || _enabledY
        {
            _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop))
            _displayLink?.add(to: RunLoop.main, forMode: RunLoop.Mode.common)
        }
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOptionX: the easing function for the animation on the x axis
    ///   - easingOptionY: the easing function for the animation on the y axis
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
    {
        animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingFunctionFromOption(easingOptionX), easingY: easingFunctionFromOption(easingOptionY))
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easing: an easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easing, easingY: easing)
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine)
    {
        animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
    }

    /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - easing: an easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        _startTimeX = CACurrentMediaTime()
        _durationX = xAxisDuration
        _endTimeX = _startTimeX + xAxisDuration
        _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
        _enabledX = xAxisDuration > 0.0
        
        _easingX = easing
        
        // Take care of the first frame if rendering is already scheduled...
        updateAnimationPhases(_startTimeX)
        
        if _enabledX || _enabledY,
            _displayLink == nil
        {
            _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop))
            _displayLink?.add(to: .main, forMode: RunLoop.Mode.common)
        }
    }
    
    /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine)
    {
        animate(xAxisDuration: xAxisDuration, easing: easingFunctionFromOption(easingOption))
    }

    /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easing: an easing function for the animation
    @objc open func animate(yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        _startTimeY = CACurrentMediaTime()
        _durationY = yAxisDuration
        _endTimeY = _startTimeY + yAxisDuration
        _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
        _enabledY = yAxisDuration > 0.0
        
        _easingY = easing
        
        // Take care of the first frame if rendering is already scheduled...
        updateAnimationPhases(_startTimeY)
        
        if _enabledX || _enabledY,
            _displayLink == nil
        {
            _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop))
            _displayLink?.add(to: .main, forMode: RunLoop.Mode.common)
        }
    }
    
    /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(yAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine)
    {
        animate(yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Animation/ChartAnimationEasing.swift
================================================
//
//  ChartAnimationUtils.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

@objc
public enum ChartEasingOption: Int
{
    case linear
    case easeInQuad
    case easeOutQuad
    case easeInOutQuad
    case easeInCubic
    case easeOutCubic
    case easeInOutCubic
    case easeInQuart
    case easeOutQuart
    case easeInOutQuart
    case easeInQuint
    case easeOutQuint
    case easeInOutQuint
    case easeInSine
    case easeOutSine
    case easeInOutSine
    case easeInExpo
    case easeOutExpo
    case easeInOutExpo
    case easeInCirc
    case easeOutCirc
    case easeInOutCirc
    case easeInElastic
    case easeOutElastic
    case easeInOutElastic
    case easeInBack
    case easeOutBack
    case easeInOutBack
    case easeInBounce
    case easeOutBounce
    case easeInOutBounce
}

public typealias ChartEasingFunctionBlock = ((_ elapsed: TimeInterval, _ duration: TimeInterval) -> Double)

internal func easingFunctionFromOption(_ easing: ChartEasingOption) -> ChartEasingFunctionBlock
{
    switch easing
    {
    case .linear:
        return EasingFunctions.Linear
    case .easeInQuad:
        return EasingFunctions.EaseInQuad
    case .easeOutQuad:
        return EasingFunctions.EaseOutQuad
    case .easeInOutQuad:
        return EasingFunctions.EaseInOutQuad
    case .easeInCubic:
        return EasingFunctions.EaseInCubic
    case .easeOutCubic:
        return EasingFunctions.EaseOutCubic
    case .easeInOutCubic:
        return EasingFunctions.EaseInOutCubic
    case .easeInQuart:
        return EasingFunctions.EaseInQuart
    case .easeOutQuart:
        return EasingFunctions.EaseOutQuart
    case .easeInOutQuart:
        return EasingFunctions.EaseInOutQuart
    case .easeInQuint:
        return EasingFunctions.EaseInQuint
    case .easeOutQuint:
        return EasingFunctions.EaseOutQuint
    case .easeInOutQuint:
        return EasingFunctions.EaseInOutQuint
    case .easeInSine:
        return EasingFunctions.EaseInSine
    case .easeOutSine:
        return EasingFunctions.EaseOutSine
    case .easeInOutSine:
        return EasingFunctions.EaseInOutSine
    case .easeInExpo:
        return EasingFunctions.EaseInExpo
    case .easeOutExpo:
        return EasingFunctions.EaseOutExpo
    case .easeInOutExpo:
        return EasingFunctions.EaseInOutExpo
    case .easeInCirc:
        return EasingFunctions.EaseInCirc
    case .easeOutCirc:
        return EasingFunctions.EaseOutCirc
    case .easeInOutCirc:
        return EasingFunctions.EaseInOutCirc
    case .easeInElastic:
        return EasingFunctions.EaseInElastic
    case .easeOutElastic:
        return EasingFunctions.EaseOutElastic
    case .easeInOutElastic:
        return EasingFunctions.EaseInOutElastic
    case .easeInBack:
        return EasingFunctions.EaseInBack
    case .easeOutBack:
        return EasingFunctions.EaseOutBack
    case .easeInOutBack:
        return EasingFunctions.EaseInOutBack
    case .easeInBounce:
        return EasingFunctions.EaseInBounce
    case .easeOutBounce:
        return EasingFunctions.EaseOutBounce
    case .easeInOutBounce:
        return EasingFunctions.EaseInOutBounce
    }
}

internal struct EasingFunctions
{
    internal static let Linear = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in return Double(elapsed / duration) }
    
    internal static let EaseInQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return position * position
    }
    
    internal static let EaseOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return -position * (position - 2.0)
    }
    
    internal static let EaseInOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / (duration / 2.0))
        if position < 1.0
        {
            return 0.5 * position * position
        }
        
        return -0.5 * ((position - 1.0) * (position - 3.0) - 1.0)
    }
    
    internal static let EaseInCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return position * position * position
    }
    
    internal static let EaseOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        position -= 1.0
        return (position * position * position + 1.0)
    }
    
    internal static let EaseInOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / (duration / 2.0))
        if position < 1.0
        {
            return 0.5 * position * position * position
        }
        position -= 2.0
        return 0.5 * (position * position * position + 2.0)
    }
    
    internal static let EaseInQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return position * position * position * position
    }
    
    internal static let EaseOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        position -= 1.0
        return -(position * position * position * position - 1.0)
    }
    
    internal static let EaseInOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / (duration / 2.0))
        if position < 1.0
        {
            return 0.5 * position * position * position * position
        }
        position -= 2.0
        return -0.5 * (position * position * position * position - 2.0)
    }
    
    internal static let EaseInQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return position * position * position * position * position
    }
    
    internal static let EaseOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        position -= 1.0
        return (position * position * position * position * position + 1.0)
    }
    
    internal static let EaseInOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / (duration / 2.0))
        if position < 1.0
        {
            return 0.5 * position * position * position * position * position
        }
        else
        {
            position -= 2.0
            return 0.5 * (position * position * position * position * position + 2.0)
        }
    }
    
    internal static let EaseInSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position: TimeInterval = elapsed / duration
        return Double( -cos(position * Double.pi / 2) + 1.0 )
    }
    
    internal static let EaseOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position: TimeInterval = elapsed / duration
        return Double( sin(position * Double.pi / 2) )
    }
    
    internal static let EaseInOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position: TimeInterval = elapsed / duration
        return Double( -0.5 * (cos(Double.pi * position) - 1.0) )
    }
    
    internal static let EaseInExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        return (elapsed == 0) ? 0.0 : Double(pow(2.0, 10.0 * (elapsed / duration - 1.0)))
    }
    
    internal static let EaseOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        return (elapsed == duration) ? 1.0 : (-Double(pow(2.0, -10.0 * elapsed / duration)) + 1.0)
    }
    
    internal static let EaseInOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        if elapsed == 0
        {
            return 0.0
        }
        if elapsed == duration
        {
            return 1.0
        }
        
        var position: TimeInterval = elapsed / (duration / 2.0)
        if position < 1.0
        {
            return Double( 0.5 * pow(2.0, 10.0 * (position - 1.0)) )
        }
        
        position = position - 1.0
        return Double( 0.5 * (-pow(2.0, -10.0 * position) + 2.0) )
    }
    
    internal static let EaseInCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        return -(Double(sqrt(1.0 - position * position)) - 1.0)
    }
    
    internal static let EaseOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position = Double(elapsed / duration)
        position -= 1.0
        return Double( sqrt(1 - position * position) )
    }
    
    internal static let EaseInOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position: TimeInterval = elapsed / (duration / 2.0)
        if position < 1.0
        {
            return Double( -0.5 * (sqrt(1.0 - position * position) - 1.0) )
        }
        position -= 2.0
        return Double( 0.5 * (sqrt(1.0 - position * position) + 1.0) )
    }
    
    internal static let EaseInElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        if elapsed == 0.0
        {
            return 0.0
        }
        
        var position: TimeInterval = elapsed / duration
        if position == 1.0
        {
            return 1.0
        }
        
        var p = duration * 0.3
        var s = p / (2.0 * Double.pi) * asin(1.0)
        position -= 1.0
        return Double( -(pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) )
    }
    
    internal static let EaseOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        if elapsed == 0.0
        {
            return 0.0
        }
        
        var position: TimeInterval = elapsed / duration
        if position == 1.0
        {
            return 1.0
        }
        
        var p = duration * 0.3
        var s = p / (2.0 * Double.pi) * asin(1.0)
        return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) + 1.0 )
    }
    
    internal static let EaseInOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        if elapsed == 0.0
        {
            return 0.0
        }
        
        var position: TimeInterval = elapsed / (duration / 2.0)
        if position == 2.0
        {
            return 1.0
        }
        
        var p = duration * (0.3 * 1.5)
        var s = p / (2.0 * Double.pi) * asin(1.0)
        if position < 1.0
        {
            position -= 1.0
            return Double( -0.5 * (pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) )
        }
        position -= 1.0
        return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) * 0.5 + 1.0 )
    }
    
    internal static let EaseInBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        let s: TimeInterval = 1.70158
        var position: TimeInterval = elapsed / duration
        return Double( position * position * ((s + 1.0) * position - s) )
    }
    
    internal static let EaseOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        let s: TimeInterval = 1.70158
        var position: TimeInterval = elapsed / duration
        position -= 1.0
        return Double( position * position * ((s + 1.0) * position + s) + 1.0 )
    }
    
    internal static let EaseInOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var s: TimeInterval = 1.70158
        var position: TimeInterval = elapsed / (duration / 2.0)
        if position < 1.0
        {
            s *= 1.525
            return Double( 0.5 * (position * position * ((s + 1.0) * position - s)) )
        }
        s *= 1.525
        position -= 2.0
        return Double( 0.5 * (position * position * ((s + 1.0) * position + s) + 2.0) )
    }
    
    internal static let EaseInBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        return 1.0 - EaseOutBounce(duration - elapsed, duration)
    }
    
    internal static let EaseOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        var position: TimeInterval = elapsed / duration
        if position < (1.0 / 2.75)
        {
            return Double( 7.5625 * position * position )
        }
        else if position < (2.0 / 2.75)
        {
            position -= (1.5 / 2.75)
            return Double( 7.5625 * position * position + 0.75 )
        }
        else if position < (2.5 / 2.75)
        {
            position -= (2.25 / 2.75)
            return Double( 7.5625 * position * position + 0.9375 )
        }
        else
        {
            position -= (2.625 / 2.75)
            return Double( 7.5625 * position * position + 0.984375 )
        }
    }
    
    internal static let EaseInOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in
        if elapsed < (duration / 2.0)
        {
            return EaseInBounce(elapsed * 2.0, duration) * 0.5
        }
        return EaseOutBounce(elapsed * 2.0 - duration, duration) * 0.5 + 0.5
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/BarChartView.swift
================================================
//
//  BarChartView.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

/// Chart that draws bars.
open class BarChartView: BarLineChartViewBase, BarChartDataProvider
{
    /// if set to true, all values are drawn above their bars, instead of below their top
    private var _drawValueAboveBarEnabled = true

    /// if set to true, a grey area is drawn behind each bar that indicates the maximum value
    private var _drawBarShadowEnabled = false
    
    internal override func initialize()
    {
        super.initialize()
        
        renderer = BarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
        
        self.highlighter = BarHighlighter(chart: self)
        
        self.xAxis.spaceMin = 0.5
        self.xAxis.spaceMax = 0.5
    }
    
    internal override func calcMinMax()
    {
        guard let data = self.data as? BarChartData
            else { return }
        
        if fitBars
        {
            _xAxis.calculate(
                min: data.xMin - data.barWidth / 2.0,
                max: data.xMax + data.barWidth / 2.0)
        }
        else
        {
            _xAxis.calculate(min: data.xMin, max: data.xMax)
        }
        
        // calculate axis range (min / max) according to provided data
        leftAxis.calculate(
            min: data.getYMin(axis: .left),
            max: data.getYMax(axis: .left))
        rightAxis.calculate(
            min: data.getYMin(axis: .right),
            max: data.getYMax(axis: .right))
    }
    
    /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the BarChart.
    open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
    {
        if _data === nil
        {
            Swift.print("Can't select by touch. No data set.")
            return nil
        }
        
        guard let h = self.highlighter?.getHighlight(x: pt.x, y: pt.y)
            else { return nil }
        
        if !isHighlightFullBarEnabled { return h }
        
        // For isHighlightFullBarEnabled, remove stackIndex
        return Highlight(
            x: h.x, y: h.y,
            xPx: h.xPx, yPx: h.yPx,
            dataIndex: h.dataIndex,
            dataSetIndex: h.dataSetIndex,
            stackIndex: -1,
            axis: h.axis)
    }
        
    /// - Returns: The bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be found in the charts data.
    @objc open func getBarBounds(entry e: BarChartDataEntry) -> CGRect
    {
        guard let
            data = _data as? BarChartData,
            let set = data.getDataSetForEntry(e) as? IBarChartDataSet
            else { return CGRect.null }
        
        let y = e.y
        let x = e.x
        
        let barWidth = data.barWidth
        
        let left = x - barWidth / 2.0
        let right = x + barWidth / 2.0
        let top = y >= 0.0 ? y : 0.0
        let bottom = y <= 0.0 ? y : 0.0
        
        var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
        
        getTransformer(forAxis: set.axisDependency).rectValueToPixel(&bounds)
        
        return bounds
    }
    
    /// Groups all BarDataSet objects this data object holds together by modifying the x-value of their entries.
    /// Previously set x-values of entries will be overwritten. Leaves space between bars and groups as specified by the parameters.
    /// Calls `notifyDataSetChanged()` afterwards.
    ///
    /// - Parameters:
    ///   - fromX: the starting point on the x-axis where the grouping should begin
    ///   - groupSpace: the space between groups of bars in values (not pixels) e.g. 0.8f for bar width 1f
    ///   - barSpace: the space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f
    @objc open func groupBars(fromX: Double, groupSpace: Double, barSpace: Double)
    {
        guard let barData = self.barData
            else
        {
            Swift.print("You need to set data for the chart before grouping bars.", terminator: "\n")
            return
        }
        
        barData.groupBars(fromX: fromX, groupSpace: groupSpace, barSpace: barSpace)
        notifyDataSetChanged()
    }
    
    /// Highlights the value at the given x-value in the given DataSet. Provide -1 as the dataSetIndex to undo all highlighting.
    ///
    /// - Parameters:
    ///   - x:
    ///   - dataSetIndex:
    ///   - stackIndex: the index inside the stack - only relevant for stacked entries
    @objc open func highlightValue(x: Double, dataSetIndex: Int, stackIndex: Int)
    {
        highlightValue(Highlight(x: x, dataSetIndex: dataSetIndex, stackIndex: stackIndex))
    }

    // MARK: Accessors
    
    /// if set to true, all values are drawn above their bars, instead of below their top
    @objc open var drawValueAboveBarEnabled: Bool
    {
        get { return _drawValueAboveBarEnabled }
        set
        {
            _drawValueAboveBarEnabled = newValue
            setNeedsDisplay()
        }
    }
    
    /// if set to true, a grey area is drawn behind each bar that indicates the maximum value
    @objc open var drawBarShadowEnabled: Bool
    {
        get { return _drawBarShadowEnabled }
        set
        {
            _drawBarShadowEnabled = newValue
            setNeedsDisplay()
        }
    }
    
    /// Adds half of the bar width to each side of the x-axis range in order to allow the bars of the barchart to be fully displayed.
    /// **default**: false
    @objc open var fitBars = false
    
    /// Set this to `true` to make the highlight operation full-bar oriented, `false` to make it highlight single values (relevant only for stacked).
    /// If enabled, highlighting operations will highlight the whole bar, even if only a single stack entry was tapped.
    @objc open var highlightFullBarEnabled: Bool = false
    
    /// `true` the highlight is be full-bar oriented, `false` ifsingle-value
    open var isHighlightFullBarEnabled: Bool { return highlightFullBarEnabled }
    
    // MARK: - BarChartDataProvider
    
    open var barData: BarChartData? { return _data as? BarChartData }
    
    /// `true` if drawing values above bars is enabled, `false` ifnot
    open var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled }
    
    /// `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot
    open var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/BarLineChartViewBase.swift
================================================
//
//  BarLineChartViewBase.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

#if canImport(UIKit)
    import UIKit
#endif

#if canImport(Cocoa)
import Cocoa
#endif

/// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart.
open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartDataProvider, NSUIGestureRecognizerDelegate
{
    /// the maximum number of entries to which values will be drawn
    /// (entry numbers greater than this value will cause value-labels to disappear)
    internal var _maxVisibleCount = 100
    
    /// flag that indicates if auto scaling on the y axis is enabled
    private var _autoScaleMinMaxEnabled = false
    
    private var _pinchZoomEnabled = false
    private var _doubleTapToZoomEnabled = true
    private var _dragXEnabled = true
    private var _dragYEnabled = true
    
    private var _scaleXEnabled = true
    private var _scaleYEnabled = true
    
    /// the color for the background of the chart-drawing area (everything behind the grid lines).
    @objc open var gridBackgroundColor = NSUIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
    
    @objc open var borderColor = NSUIColor.black
    @objc open var borderLineWidth: CGFloat = 1.0
    
    /// flag indicating if the grid background should be drawn or not
    @objc open var drawGridBackgroundEnabled = false
    
    /// When enabled, the borders rectangle will be rendered.
    /// If this is enabled, there is no point drawing the axis-lines of x- and y-axis.
    @objc open var drawBordersEnabled = false
    
    /// When enabled, the values will be clipped to contentRect, otherwise they can bleed outside the content rect.
    @objc open var clipValuesToContentEnabled: Bool = false

    /// When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can
    /// be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines)
    /// that there is unwanted clipping.
    @objc open var clipDataToContentEnabled: Bool = true

    /// Sets the minimum offset (padding) around the chart, defaults to 10
    @objc open var minOffset = CGFloat(10.0)
    
    /// Sets whether the chart should keep its position (zoom / scroll) after a rotation (orientation change)
    /// **default**: false
    @objc open var keepPositionOnRotation: Bool = false
    
    /// The left y-axis object. In the horizontal bar-chart, this is the
    /// top axis.
    @objc open internal(set) var leftAxis = YAxis(position: .left)
    
    /// The right y-axis object. In the horizontal bar-chart, this is the
    /// bottom axis.
    @objc open internal(set) var rightAxis = YAxis(position: .right)

    /// The left Y axis renderer. This is a read-write property so you can set your own custom renderer here.
    /// **default**: An instance of YAxisRenderer
    @objc open lazy var leftYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer)

    /// The right Y axis renderer. This is a read-write property so you can set your own custom renderer here.
    /// **default**: An instance of YAxisRenderer
    @objc open lazy var rightYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer)
    
    internal var _leftAxisTransformer: Transformer!
    internal var _rightAxisTransformer: Transformer!
    
    /// The X axis renderer. This is a read-write property so you can set your own custom renderer here.
    /// **default**: An instance of XAxisRenderer
    @objc open lazy var xAxisRenderer = XAxisRenderer(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer)
    
    internal var _tapGestureRecognizer: NSUITapGestureRecognizer!
    internal var _doubleTapGestureRecognizer: NSUITapGestureRecognizer!
    #if !os(tvOS)
    internal var _pinchGestureRecognizer: NSUIPinchGestureRecognizer!
    #endif
    internal var _panGestureRecognizer: NSUIPanGestureRecognizer!
    
    /// flag that indicates if a custom viewport offset has been set
    private var _customViewPortEnabled = false
    
    public override init(frame: CGRect)
    {
        super.init(frame: frame)
    }
    
    public required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
    }
    
    deinit
    {
        stopDeceleration()
    }
    
    internal override func initialize()
    {
        super.initialize()

        _leftAxisTransformer = Transformer(viewPortHandler: _viewPortHandler)
        _rightAxisTransformer = Transformer(viewPortHandler: _viewPortHandler)
        
        self.highlighter = ChartHighlighter(chart: self)
        
        _tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:)))
        _doubleTapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognized(_:)))
        _doubleTapGestureRecognizer.nsuiNumberOfTapsRequired = 2
        _panGestureRecognizer = NSUIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
        
        _panGestureRecognizer.delegate = self
        
        self.addGestureRecognizer(_tapGestureRecognizer)
        self.addGestureRecognizer(_doubleTapGestureRecognizer)
        self.addGestureRecognizer(_panGestureRecognizer)
        
        _doubleTapGestureRecognizer.isEnabled = _doubleTapToZoomEnabled
        _panGestureRecognizer.isEnabled = _dragXEnabled || _dragYEnabled

        #if !os(tvOS)
        _pinchGestureRecognizer = NSUIPinchGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.pinchGestureRecognized(_:)))
        _pinchGestureRecognizer.delegate = self
        self.addGestureRecognizer(_pinchGestureRecognizer)
        _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
        #endif
    }
    
    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
    {
        // Saving current position of chart.
        var oldPoint: CGPoint?
        if (keepPositionOnRotation && (keyPath == "frame" || keyPath == "bounds"))
        {
            oldPoint = viewPortHandler.contentRect.origin
            getTransformer(forAxis: .left).pixelToValues(&oldPoint!)
        }
        
        // Superclass transforms chart.
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        
        // Restoring old position of chart
        if var newPoint = oldPoint , keepPositionOnRotation
        {
            getTransformer(forAxis: .left).pointValueToPixel(&newPoint)
            viewPortHandler.centerViewPort(pt: newPoint, chart: self)
        }
        else
        {
            viewPortHandler.refresh(newMatrix: viewPortHandler.touchMatrix, chart: self, invalidate: true)
        }
    }
    
    open override func draw(_ rect: CGRect)
    {
        super.draw(rect)

        guard data != nil, let renderer = renderer else { return }
        
        let optionalContext = NSUIGraphicsGetCurrentContext()
        guard let context = optionalContext else { return }

        // execute all drawing commands
        drawGridBackground(context: context)
        

        if _autoScaleMinMaxEnabled
        {
            autoScale()
        }

        if leftAxis.isEnabled
        {
            leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted)
        }
        
        if rightAxis.isEnabled
        {
            rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted)
        }
        
        if _xAxis.isEnabled
        {
            xAxisRenderer.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false)
        }
        
        xAxisRenderer.renderAxisLine(context: context)
        leftYAxisRenderer.renderAxisLine(context: context)
        rightYAxisRenderer.renderAxisLine(context: context)

        // The renderers are responsible for clipping, to account for line-width center etc.
        if xAxis.drawGridLinesBehindDataEnabled
        {
            xAxisRenderer.renderGridLines(context: context)
            leftYAxisRenderer.renderGridLines(context: context)
            rightYAxisRenderer.renderGridLines(context: context)
        }
        
        if _xAxis.isEnabled && _xAxis.isDrawLimitLinesBehindDataEnabled
        {
            xAxisRenderer.renderLimitLines(context: context)
        }
        
        if leftAxis.isEnabled && leftAxis.isDrawLimitLinesBehindDataEnabled
        {
            leftYAxisRenderer.renderLimitLines(context: context)
        }
        
        if rightAxis.isEnabled && rightAxis.isDrawLimitLinesBehindDataEnabled
        {
            rightYAxisRenderer.renderLimitLines(context: context)
        }
        
        context.saveGState()
        // make sure the data cannot be drawn outside the content-rect
        if clipDataToContentEnabled {
            context.clip(to: _viewPortHandler.contentRect)
        }
        renderer.drawData(context: context)
        
        // The renderers are responsible for clipping, to account for line-width center etc.
        if !xAxis.drawGridLinesBehindDataEnabled
        {
            xAxisRenderer.renderGridLines(context: context)
            leftYAxisRenderer.renderGridLines(context: context)
            rightYAxisRenderer.renderGridLines(context: context)
        }
        
        // if highlighting is enabled
        if (valuesToHighlight())
        {
            renderer.drawHighlighted(context: context, indices: _indicesToHighlight)
        }
        
        context.restoreGState()
        
        renderer.drawExtras(context: context)
        
        if _xAxis.isEnabled && !_xAxis.isDrawLimitLinesBehindDataEnabled
        {
            xAxisRenderer.renderLimitLines(context: context)
        }
        
        if leftAxis.isEnabled && !leftAxis.isDrawLimitLinesBehindDataEnabled
        {
            leftYAxisRenderer.renderLimitLines(context: context)
        }
        
        if rightAxis.isEnabled && !rightAxis.isDrawLimitLinesBehindDataEnabled
        {
            rightYAxisRenderer.renderLimitLines(context: context)
        }
        
        xAxisRenderer.renderAxisLabels(context: context)
        leftYAxisRenderer.renderAxisLabels(context: context)
        rightYAxisRenderer.renderAxisLabels(context: context)

        if clipValuesToContentEnabled
        {
            context.saveGState()
            context.clip(to: _viewPortHandler.contentRect)
            
            renderer.drawValues(context: context)
            
            context.restoreGState()
        }
        else
        {
            renderer.drawValues(context: context)
        }

        _legendRenderer.renderLegend(context: context)

        drawDescription(context: context)
        
        drawMarkers(context: context)
    }
    
    private var _autoScaleLastLowestVisibleX: Double?
    private var _autoScaleLastHighestVisibleX: Double?
    
    /// Performs auto scaling of the axis by recalculating the minimum and maximum y-values based on the entries currently in view.
    internal func autoScale()
    {
        guard let data = _data
            else { return }
        
        data.calcMinMaxY(fromX: self.lowestVisibleX, toX: self.highestVisibleX)
        
        _xAxis.calculate(min: data.xMin, max: data.xMax)
        
        // calculate axis range (min / max) according to provided data
        
        if leftAxis.isEnabled
        {
            leftAxis.calculate(min: data.getYMin(axis: .left), max: data.getYMax(axis: .left))
        }
        
        if rightAxis.isEnabled
        {
            rightAxis.calculate(min: data.getYMin(axis: .right), max: data.getYMax(axis: .right))
        }
        
        calculateOffsets()
    }
    
    internal func prepareValuePxMatrix()
    {
        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: _xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(rightAxis.axisRange), chartYMin: rightAxis._axisMinimum)
        _leftAxisTransformer.prepareMatrixValuePx(chartXMin: xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(leftAxis.axisRange), chartYMin: leftAxis._axisMinimum)
    }
    
    internal func prepareOffsetMatrix()
    {
        _rightAxisTransformer.prepareMatrixOffset(inverted: rightAxis.isInverted)
        _leftAxisTransformer.prepareMatrixOffset(inverted: leftAxis.isInverted)
    }
    
    open override func notifyDataSetChanged()
    {
        renderer?.initBuffers()
        
        calcMinMax()
        
        leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted)
        rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted)
        
        if let data = _data
        {
            xAxisRenderer.computeAxis(
                min: _xAxis._axisMinimum,
                max: _xAxis._axisMaximum,
                inverted: false)

            if _legend !== nil
            {
                legendRenderer?.computeLegend(data: data)
            }
        }
        
        calculateOffsets()
        
        setNeedsDisplay()
    }
    
    internal override func calcMinMax()
    {
        // calculate / set x-axis range
        _xAxis.calculate(min: _data?.xMin ?? 0.0, max: _data?.xMax ?? 0.0)
        
        // calculate axis range (min / max) according to provided data
        leftAxis.calculate(min: _data?.getYMin(axis: .left) ?? 0.0, max: _data?.getYMax(axis: .left) ?? 0.0)
        rightAxis.calculate(min: _data?.getYMin(axis: .right) ?? 0.0, max: _data?.getYMax(axis: .right) ?? 0.0)
    }
    
    internal func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat)
    {
        // setup offsets for legend
        if _legend !== nil && _legend.isEnabled && !_legend.drawInside
        {
            switch _legend.orientation
            {
            case .vertical:
                
                switch _legend.horizontalAlignment
                {
                case .left:
                    offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset
                    
                case .right:
                    offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset
                    
                case .center:
                    
                    switch _legend.verticalAlignment
                    {
                    case .top:
                        offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
                        
                    case .bottom:
                        offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
                        
                    default:
                        break
                    }
                }
                
            case .horizontal:
                
                switch _legend.verticalAlignment
                {
                case .top:
                    offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
                    
                case .bottom:
                    offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
                    
                default:
                    break
                }
            }
        }
    }
    
    internal override func calculateOffsets()
    {
        if !_customViewPortEnabled
        {
            var offsetLeft = CGFloat(0.0)
            var offsetRight = CGFloat(0.0)
            var offsetTop = CGFloat(0.0)
            var offsetBottom = CGFloat(0.0)
            
            calculateLegendOffsets(offsetLeft: &offsetLeft,
                                   offsetTop: &offsetTop,
                                   offsetRight: &offsetRight,
                                   offsetBottom: &offsetBottom)
            
            // offsets for y-labels
            if leftAxis.needsOffset
            {
                offsetLeft += leftAxis.requiredSize().width
            }
            
            if rightAxis.needsOffset
            {
                offsetRight += rightAxis.requiredSize().width
            }

            if xAxis.isEnabled && xAxis.isDrawLabelsEnabled
            {
                let xlabelheight = xAxis.labelRotatedHeight + xAxis.yOffset
                
                // offsets for x-labels
                if xAxis.labelPosition == .bottom
                {
                    offsetBottom += xlabelheight
                }
                else if xAxis.labelPosition == .top
                {
                    offsetTop += xlabelheight
                }
                else if xAxis.labelPosition == .bothSided
                {
                    offsetBottom += xlabelheight
                    offsetTop += xlabelheight
                }
            }
            
            offsetTop += self.extraTopOffset
            offsetRight += self.extraRightOffset
            offsetBottom += self.extraBottomOffset
            offsetLeft += self.extraLeftOffset

            _viewPortHandler.restrainViewPort(
                offsetLeft: max(self.minOffset, offsetLeft),
                offsetTop: max(self.minOffset, offsetTop),
                offsetRight: max(self.minOffset, offsetRight),
                offsetBottom: max(self.minOffset, offsetBottom))
        }
        
        prepareOffsetMatrix()
        prepareValuePxMatrix()
    }
    
    /// draws the grid background
    internal func drawGridBackground(context: CGContext)
    {
        if drawGridBackgroundEnabled || drawBordersEnabled
        {
            context.saveGState()
        }
        
        if drawGridBackgroundEnabled
        {
            // draw the grid background
            context.setFillColor(gridBackgroundColor.cgColor)
            context.fill(_viewPortHandler.contentRect)
        }
        
        if drawBordersEnabled
        {
            context.setLineWidth(borderLineWidth)
            context.setStrokeColor(borderColor.cgColor)
            context.stroke(_viewPortHandler.contentRect)
        }
        
        if drawGridBackgroundEnabled || drawBordersEnabled
        {
            context.restoreGState()
        }
    }
    
    // MARK: - Gestures
    
    private enum GestureScaleAxis
    {
        case both
        case x
        case y
    }
    
    private var _isDragging = false
    private var _isScaling = false
    private var _gestureScaleAxis = GestureScaleAxis.both
    private var _closestDataSetToTouch: IChartDataSet!
    private var _panGestureReachedEdge: Bool = false
    private weak var _outerScrollView: NSUIScrollView?
    
    private var _lastPanPoint = CGPoint() /// This is to prevent using setTranslation which resets velocity
    
    private var _decelerationLastTime: TimeInterval = 0.0
    private var _decelerationDisplayLink: NSUIDisplayLink!
    private var _decelerationVelocity = CGPoint()
    
    @objc private func tapGestureRecognized(_ recognizer: NSUITapGestureRecognizer)
    {
        if _data === nil
        {
            return
        }
        
        if recognizer.state == NSUIGestureRecognizerState.ended
        {
            if !isHighLightPerTapEnabled { return }
            
            let h = getHighlightByTouchPoint(recognizer.location(in: self))
            
            if h === nil || h == self.lastHighlighted
            {
                lastHighlighted = nil
                highlightValue(nil, callDelegate: true)
            }
            else
            {
                lastHighlighted = h
                highlightValue(h, callDelegate: true)
            }
        }
    }
    
    @objc private func doubleTapGestureRecognized(_ recognizer: NSUITapGestureRecognizer)
    {
        if _data === nil
        {
            return
        }
        
        if recognizer.state == NSUIGestureRecognizerState.ended
        {
            if _data !== nil && _doubleTapToZoomEnabled && (data?.entryCount ?? 0) > 0
            {
                var location = recognizer.location(in: self)
                location.x = location.x - _viewPortHandler.offsetLeft
                
                if isTouchInverted()
                {
                    location.y = -(location.y - _viewPortHandler.offsetTop)
                }
                else
                {
                    location.y = -(self.bounds.size.height - location.y - _viewPortHandler.offsetBottom)
                }

                let scaleX: CGFloat = isScaleXEnabled ? 1.4 : 1.0
                let scaleY: CGFloat = isScaleYEnabled ? 1.4 : 1.0

                self.zoom(scaleX: scaleX, scaleY: scaleY, x: location.x, y: location.y)
                delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
            }
        }
    }
    
    #if !os(tvOS)
    @objc private func pinchGestureRecognized(_ recognizer: NSUIPinchGestureRecognizer)
    {
        if recognizer.state == NSUIGestureRecognizerState.began
        {
            stopDeceleration()
            
            if _data !== nil &&
                (_pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled)
            {
                _isScaling = true
                
                if _pinchZoomEnabled
                {
                    _gestureScaleAxis = .both
                }
                else
                {
                    let x = abs(recognizer.location(in: self).x - recognizer.nsuiLocationOfTouch(1, inView: self).x)
                    let y = abs(recognizer.location(in: self).y - recognizer.nsuiLocationOfTouch(1, inView: self).y)
                    
                    if _scaleXEnabled != _scaleYEnabled
                    {
                        _gestureScaleAxis = _scaleXEnabled ? .x : .y
                    }
                    else
                    {
                        _gestureScaleAxis = x > y ? .x : .y
                    }
                }
            }
        }
        else if recognizer.state == NSUIGestureRecognizerState.ended ||
            recognizer.state == NSUIGestureRecognizerState.cancelled
        {
            if _isScaling
            {
                _isScaling = false
                
                // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
                calculateOffsets()
                setNeedsDisplay()
            }
        }
        else if recognizer.state == NSUIGestureRecognizerState.changed
        {
            let isZoomingOut = (recognizer.nsuiScale < 1)
            var canZoomMoreX = isZoomingOut ? _viewPortHandler.canZoomOutMoreX : _viewPortHandler.canZoomInMoreX
            var canZoomMoreY = isZoomingOut ? _viewPortHandler.canZoomOutMoreY : _viewPortHandler.canZoomInMoreY
            
            if _isScaling
            {
                canZoomMoreX = canZoomMoreX && _scaleXEnabled && (_gestureScaleAxis == .both || _gestureScaleAxis == .x)
                canZoomMoreY = canZoomMoreY && _scaleYEnabled && (_gestureScaleAxis == .both || _gestureScaleAxis == .y)
                if canZoomMoreX || canZoomMoreY
                {
                    var location = recognizer.location(in: self)
                    location.x = location.x - _viewPortHandler.offsetLeft
                    
                    if isTouchInverted()
                    {
                        location.y = -(location.y - _viewPortHandler.offsetTop)
                    }
                    else
                    {
                        location.y = -(_viewPortHandler.chartHeight - location.y - _viewPortHandler.offsetBottom)
                    }
                    
                    let scaleX = canZoomMoreX ? recognizer.nsuiScale : 1.0
                    let scaleY = canZoomMoreY ? recognizer.nsuiScale : 1.0
                    
                    var matrix = CGAffineTransform(translationX: location.x, y: location.y)
                    matrix = matrix.scaledBy(x: scaleX, y: scaleY)
                    matrix = matrix.translatedBy(x: -location.x, y: -location.y)
                    
                    matrix = _viewPortHandler.touchMatrix.concatenating(matrix)
                    
                    _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
                    
                    if delegate !== nil
                    {
                        delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
                    }
                }
                
                recognizer.nsuiScale = 1.0
            }
        }
    }
    #endif
    
    @objc private func panGestureRecognized(_ recognizer: NSUIPanGestureRecognizer)
    {
        if recognizer.state == NSUIGestureRecognizerState.began && recognizer.nsuiNumberOfTouches() > 0
        {
            stopDeceleration()
            
            if _data === nil || !self.isDragEnabled
            { // If we have no data, we have nothing to pan and no data to highlight
                return
            }
            
            // If drag is enabled and we are in a position where there's something to drag:
            //  * If we're zoomed in, then obviously we have something to drag.
            //  * If we have a drag offset - we always have something to drag
            if !self.hasNoDragOffset || !self.isFullyZoomedOut
            {
                _isDragging = true
                
                _closestDataSetToTouch = getDataSetByTouchPoint(point: recognizer.nsuiLocationOfTouch(0, inView: self))
                
                var translation = recognizer.translation(in: self)
                if !self.dragXEnabled
                {
                    translation.x = 0.0
                }
                else if !self.dragYEnabled
                {
                    translation.y = 0.0
                }
                
                let didUserDrag = translation.x != 0.0 || translation.y != 0.0
                
                // Check to see if user dragged at all and if so, can the chart be dragged by the given amount
                if didUserDrag && !performPanChange(translation: translation)
                {
                    if _outerScrollView !== nil
                    {
                        // We can stop dragging right now, and let the scroll view take control
                        _outerScrollView = nil
                        _isDragging = false
                    }
                }
                else
                {
                    if _outerScrollView !== nil
                    {
                        // Prevent the parent scroll view from scrolling
                        _outerScrollView?.nsuiIsScrollEnabled = false
                    }
                }
                
                _lastPanPoint = recognizer.translation(in: self)
            }
            else if self.isHighlightPerDragEnabled
            {
                // We will only handle highlights on NSUIGestureRecognizerState.Changed
                
                _isDragging = false
            }
        }
        else if recognizer.state == NSUIGestureRecognizerState.changed
        {
            if _isDragging
            {
                let originalTranslation = recognizer.translation(in: self)
                var translation = CGPoint(x: originalTranslation.x - _lastPanPoint.x, y: originalTranslation.y - _lastPanPoint.y)
                
                if !self.dragXEnabled
                {
                    translation.x = 0.0
                }
                else if !self.dragYEnabled
                {
                    translation.y = 0.0
                }
                
                let _ = performPanChange(translation: translation)
                
                _lastPanPoint = originalTranslation
            }
            else if isHighlightPerDragEnabled
            {
                let h = getHighlightByTouchPoint(recognizer.location(in: self))
                
                let lastHighlighted = self.lastHighlighted
                
                if h != lastHighlighted
                {
                    self.lastHighlighted = h
                    self.highlightValue(h, callDelegate: true)
                }
            }
        }
        else if recognizer.state == NSUIGestureRecognizerState.ended || recognizer.state == NSUIGestureRecognizerState.cancelled
        {
            if _isDragging
            {
                if recognizer.state == NSUIGestureRecognizerState.ended && isDragDecelerationEnabled
                {
                    stopDeceleration()
                    
                    _decelerationLastTime = CACurrentMediaTime()
                    _decelerationVelocity = recognizer.velocity(in: self)
                    
                    _decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(BarLineChartViewBase.decelerationLoop))
                    _decelerationDisplayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common)
                }
                
                _isDragging = false
                
                delegate?.chartViewDidEndPanning?(self)
            }
            
            if _outerScrollView !== nil
            {
                _outerScrollView?.nsuiIsScrollEnabled = true
                _outerScrollView = nil
            }
        }
    }
    
    private func performPanChange(translation: CGPoint) -> Bool
    {
        var translation = translation
        
        if isTouchInverted()
        {
            if self is HorizontalBarChartView
            {
                translation.x = -translation.x
            }
            else
            {
                translation.y = -translation.y
            }
        }
        
        let originalMatrix = _viewPortHandler.touchMatrix
        
        var matrix = CGAffineTransform(translationX: translation.x, y: translation.y)
        matrix = originalMatrix.concatenating(matrix)
        
        matrix = _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
        
        if matrix != originalMatrix
        {
            delegate?.chartTranslated?(self, dX: translation.x, dY: translation.y)
        }
        
        // Did we managed to actually drag or did we reach the edge?
        return matrix.tx != originalMatrix.tx || matrix.ty != originalMatrix.ty
    }
    
    private func isTouchInverted() -> Bool
    {
        return isAnyAxisInverted &&
            _closestDataSetToTouch !== nil &&
            getAxis(_closestDataSetToTouch.axisDependency).isInverted
    }
    
    @objc open func stopDeceleration()
    {
        if _decelerationDisplayLink !== nil
        {
            _decelerationDisplayLink.remove(from: RunLoop.main, forMode: RunLoop.Mode.common)
            _decelerationDisplayLink = nil
        }
    }
    
    @objc private func decelerationLoop()
    {
        let currentTime = CACurrentMediaTime()
        
        _decelerationVelocity.x *= self.dragDecelerationFrictionCoef
        _decelerationVelocity.y *= self.dragDecelerationFrictionCoef
        
        let timeInterval = CGFloat(currentTime - _decelerationLastTime)
        
        let distance = CGPoint(
            x: _decelerationVelocity.x * timeInterval,
            y: _decelerationVelocity.y * timeInterval
        )
        
        if !performPanChange(translation: distance)
        {
            // We reached the edge, stop
            _decelerationVelocity.x = 0.0
            _decelerationVelocity.y = 0.0
        }
        
        _decelerationLastTime = currentTime
        
        if abs(_decelerationVelocity.x) < 0.001 && abs(_decelerationVelocity.y) < 0.001
        {
            stopDeceleration()
            
            // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
            calculateOffsets()
            setNeedsDisplay()
        }
    }
    
    private func nsuiGestureRecognizerShouldBegin(_ gestureRecognizer: NSUIGestureRecognizer) -> Bool
    {
        if gestureRecognizer == _panGestureRecognizer
        {
            let velocity = _panGestureRecognizer.velocity(in: self)
            if _data === nil || !isDragEnabled ||
                (self.hasNoDragOffset && self.isFullyZoomedOut && !self.isHighlightPerDragEnabled) ||
                (!_dragYEnabled && abs(velocity.y) > abs(velocity.x)) ||
                (!_dragXEnabled && abs(velocity.y) < abs(velocity.x))
            {
                return false
            }
        }
        else
        {
            #if !os(tvOS)
            if gestureRecognizer == _pinchGestureRecognizer
            {
                if _data === nil || (!_pinchZoomEnabled && !_scaleXEnabled && !_scaleYEnabled)
                {
                    return false
                }
            }
            #endif
        }
        
        return true
    }
    
    #if !os(OSX)
    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
    {
        if !super.gestureRecognizerShouldBegin(gestureRecognizer)
        {
            return false
        }
        
        return nsuiGestureRecognizerShouldBegin(gestureRecognizer)
    }
    #endif
    
    #if os(OSX)
    public func gestureRecognizerShouldBegin(gestureRecognizer: NSGestureRecognizer) -> Bool
    {
        return nsuiGestureRecognizerShouldBegin(gestureRecognizer)
    }
    #endif
    
    open func gestureRecognizer(_ gestureRecognizer: NSUIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSUIGestureRecognizer) -> Bool
    {
        #if !os(tvOS)
        if ((gestureRecognizer is NSUIPinchGestureRecognizer && otherGestureRecognizer is NSUIPanGestureRecognizer) ||
            (gestureRecognizer is NSUIPanGestureRecognizer && otherGestureRecognizer is NSUIPinchGestureRecognizer))
        {
            return true
        }
        #endif
        
        if gestureRecognizer is NSUIPanGestureRecognizer,
            otherGestureRecognizer is NSUIPanGestureRecognizer,
            gestureRecognizer == _panGestureRecognizer
        {
            var scrollView = self.superview
            while scrollView != nil && !(scrollView is NSUIScrollView)
            {
                scrollView = scrollView?.superview
            }
            
            // If there is two scrollview together, we pick the superview of the inner scrollview.
            // In the case of UITableViewWrepperView, the superview will be UITableView
            if let superViewOfScrollView = scrollView?.superview,
                superViewOfScrollView is NSUIScrollView
            {
                scrollView = superViewOfScrollView
            }

            var foundScrollView = scrollView as? NSUIScrollView
            
            if !(foundScrollView?.nsuiIsScrollEnabled ?? true)
            {
                foundScrollView = nil
            }
            
            let scrollViewPanGestureRecognizer = foundScrollView?.nsuiGestureRecognizers?.first {
                $0 is NSUIPanGestureRecognizer
            }
            
            if otherGestureRecognizer === scrollViewPanGestureRecognizer
            {
                _outerScrollView = foundScrollView
                
                return true
            }
        }
        
        return false
    }
    
    /// MARK: Viewport modifiers
    
    /// Zooms in by 1.4, into the charts center.
    @objc open func zoomIn()
    {
        let center = _viewPortHandler.contentCenter
        
        let matrix = _viewPortHandler.zoomIn(x: center.x, y: -center.y)
        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
        
        // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
        calculateOffsets()
        setNeedsDisplay()
    }

    /// Zooms out by 0.7, from the charts center.
    @objc open func zoomOut()
    {
        let center = _viewPortHandler.contentCenter
        
        let matrix = _viewPortHandler.zoomOut(x: center.x, y: -center.y)
        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)

        // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
        calculateOffsets()
        setNeedsDisplay()
    }
    
    /// Zooms out to original size.
    @objc open func resetZoom()
    {
        let matrix = _viewPortHandler.resetZoom()
        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
        
        // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
        calculateOffsets()
        setNeedsDisplay()
    }

    /// Zooms in or out by the given scale factor. x and y are the coordinates
    /// (in pixels) of the zoom center.
    ///
    /// - Parameters:
    ///   - scaleX: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - scaleY: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - x:
    ///   - y:
    @objc open func zoom(
        scaleX: CGFloat,
               scaleY: CGFloat,
               x: CGFloat,
               y: CGFloat)
    {
        let matrix = _viewPortHandler.zoom(scaleX: scaleX, scaleY: scaleY, x: x, y: -y)
        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
        
        // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
        calculateOffsets()
        setNeedsDisplay()
    }
    
    /// Zooms in or out by the given scale factor.
    /// x and y are the values (**not pixels**) of the zoom center.
    ///
    /// - Parameters:
    ///   - scaleX: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - scaleY: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - xValue:
    ///   - yValue:
    ///   - axis:
    @objc open func zoom(
        scaleX: CGFloat,
               scaleY: CGFloat,
               xValue: Double,
               yValue: Double,
               axis: YAxis.AxisDependency)
    {
        let job = ZoomViewJob(
            viewPortHandler: viewPortHandler,
            scaleX: scaleX,
            scaleY: scaleY,
            xValue: xValue,
            yValue: yValue,
            transformer: getTransformer(forAxis: axis),
            axis: axis,
            view: self)
        addViewportJob(job)
    }
    
    /// Zooms to the center of the chart with the given scale factor.
    ///
    /// - Parameters:
    ///   - scaleX: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - scaleY: if < 1 --> zoom out, if > 1 --> zoom in
    ///   - xValue:
    ///   - yValue:
    ///   - axis:
    @objc open func zoomToCenter(
        scaleX: CGFloat,
               scaleY: CGFloat)
    {
        let center = centerOffsets
        let matrix = viewPortHandler.zoom(
            scaleX: scaleX,
            scaleY: scaleY,
            x: center.x,
            y: -center.y)
        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
    }
    
    /// Zooms by the specified scale factor to the specified values on the specified axis.
    ///
    /// - Parameters:
    ///   - scaleX:
    ///   - scaleY:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func zoomAndCenterViewAnimated(
        scaleX: CGFloat,
        scaleY: CGFloat,
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easing: ChartEasingFunctionBlock?)
    {
        let origin = valueForTouchPoint(
            point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
            axis: axis)
        
        let job = AnimatedZoomViewJob(
            viewPortHandler: viewPortHandler,
            transformer: getTransformer(forAxis: axis),
            view: self,
            yAxis: getAxis(axis),
            xAxisRange: _xAxis.axisRange,
            scaleX: scaleX,
            scaleY: scaleY,
            xOrigin: viewPortHandler.scaleX,
            yOrigin: viewPortHandler.scaleY,
            zoomCenterX: CGFloat(xValue),
            zoomCenterY: CGFloat(yValue),
            zoomOriginX: origin.x,
            zoomOriginY: origin.y,
            duration: duration,
            easing: easing)
            
        addViewportJob(job)
    }
    
    /// Zooms by the specified scale factor to the specified values on the specified axis.
    ///
    /// - Parameters:
    ///   - scaleX:
    ///   - scaleY:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func zoomAndCenterViewAnimated(
        scaleX: CGFloat,
        scaleY: CGFloat,
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easingOption: ChartEasingOption)
    {
        zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
    }
    
    /// Zooms by the specified scale factor to the specified values on the specified axis.
    ///
    /// - Parameters:
    ///   - scaleX:
    ///   - scaleY:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func zoomAndCenterViewAnimated(
        scaleX: CGFloat,
        scaleY: CGFloat,
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval)
    {
        zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine)
    }
    
    /// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
    @objc open func fitScreen()
    {
        let matrix = _viewPortHandler.fitScreen()
        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
        
        calculateOffsets()
        setNeedsDisplay()
    }
    
    /// Sets the minimum scale value to which can be zoomed out. 1 = fitScreen
    @objc open func setScaleMinima(_ scaleX: CGFloat, scaleY: CGFloat)
    {
        _viewPortHandler.setMinimumScaleX(scaleX)
        _viewPortHandler.setMinimumScaleY(scaleY)
    }
    
    @objc open var visibleXRange: Double
    {
        return abs(highestVisibleX - lowestVisibleX)
    }
    
    /// Sets the size of the area (range on the x-axis) that should be maximum visible at once (no further zooming out allowed).
    ///
    /// If this is e.g. set to 10, no more than a range of 10 values on the x-axis can be viewed at once without scrolling.
    ///
    /// If you call this method, chart must have data or it has no effect.
    @objc open func setVisibleXRangeMaximum(_ maxXRange: Double)
    {
        let xScale = _xAxis.axisRange / maxXRange
        _viewPortHandler.setMinimumScaleX(CGFloat(xScale))
    }
    
    /// Sets the size of the area (range on the x-axis) that should be minimum visible at once (no further zooming in allowed).
    ///
    /// If this is e.g. set to 10, no less than a range of 10 values on the x-axis can be viewed at once without scrolling.
    ///
    /// If you call this method, chart must have data or it has no effect.
    @objc open func setVisibleXRangeMinimum(_ minXRange: Double)
    {
        let xScale = _xAxis.axisRange / minXRange
        _viewPortHandler.setMaximumScaleX(CGFloat(xScale))
    }

    /// Limits the maximum and minimum value count that can be visible by pinching and zooming.
    ///
    /// e.g. minRange=10, maxRange=100 no less than 10 values and no more that 100 values can be viewed
    /// at once without scrolling.
    ///
    /// If you call this method, chart must have data or it has no effect.
    @objc open func setVisibleXRange(minXRange: Double, maxXRange: Double)
    {
        let minScale = _xAxis.axisRange / maxXRange
        let maxScale = _xAxis.axisRange / minXRange
        _viewPortHandler.setMinMaxScaleX(
            minScaleX: CGFloat(minScale),
            maxScaleX: CGFloat(maxScale))
    }
    
    /// Sets the size of the area (range on the y-axis) that should be maximum visible at once.
    ///
    /// - Parameters:
    ///   - yRange:
    ///   - axis: - the axis for which this limit should apply
    @objc open func setVisibleYRangeMaximum(_ maxYRange: Double, axis: YAxis.AxisDependency)
    {
        let yScale = getAxisRange(axis: axis) / maxYRange
        _viewPortHandler.setMinimumScaleY(CGFloat(yScale))
    }
    
    /// Sets the size of the area (range on the y-axis) that should be minimum visible at once, no further zooming in possible.
    ///
    /// - Parameters:
    ///   - yRange:
    ///   - axis: - the axis for which this limit should apply
    @objc open func setVisibleYRangeMinimum(_ minYRange: Double, axis: YAxis.AxisDependency)
    {
        let yScale = getAxisRange(axis: axis) / minYRange
        _viewPortHandler.setMaximumScaleY(CGFloat(yScale))
    }

    /// Limits the maximum and minimum y range that can be visible by pinching and zooming.
    ///
    /// - Parameters:
    ///   - minYRange:
    ///   - maxYRange:
    ///   - axis:
    @objc open func setVisibleYRange(minYRange: Double, maxYRange: Double, axis: YAxis.AxisDependency)
    {
        let minScale = getAxisRange(axis: axis) / minYRange
        let maxScale = getAxisRange(axis: axis) / maxYRange
        _viewPortHandler.setMinMaxScaleY(minScaleY: CGFloat(minScale), maxScaleY: CGFloat(maxScale))
    }
    
    /// Moves the left side of the current viewport to the specified x-value.
    /// This also refreshes the chart by calling setNeedsDisplay().
    @objc open func moveViewToX(_ xValue: Double)
    {
        let job = MoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: xValue,
            yValue: 0.0,
            transformer: getTransformer(forAxis: .left),
            view: self)
        
        addViewportJob(job)
    }

    /// Centers the viewport to the specified y-value on the y-axis.
    /// This also refreshes the chart by calling setNeedsDisplay().
    /// 
    /// - Parameters:
    ///   - yValue:
    ///   - axis: - which axis should be used as a reference for the y-axis
    @objc open func moveViewToY(_ yValue: Double, axis: YAxis.AxisDependency)
    {
        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
        
        let job = MoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: 0.0,
            yValue: yValue + yInView / 2.0,
            transformer: getTransformer(forAxis: axis),
            view: self)
        
        addViewportJob(job)
    }

    /// This will move the left side of the current viewport to the specified x-value on the x-axis, and center the viewport to the specified y-value on the y-axis.
    /// This also refreshes the chart by calling setNeedsDisplay().
    /// 
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: - which axis should be used as a reference for the y-axis
    @objc open func moveViewTo(xValue: Double, yValue: Double, axis: YAxis.AxisDependency)
    {
        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
        
        let job = MoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: xValue,
            yValue: yValue + yInView / 2.0,
            transformer: getTransformer(forAxis: axis),
            view: self)
        
        addViewportJob(job)
    }
    
    /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
    /// This also refreshes the chart by calling setNeedsDisplay().
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func moveViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easing: ChartEasingFunctionBlock?)
    {
        let bounds = valueForTouchPoint(
            point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
            axis: axis)
        
        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
        
        let job = AnimatedMoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: xValue,
            yValue: yValue + yInView / 2.0,
            transformer: getTransformer(forAxis: axis),
            view: self,
            xOrigin: bounds.x,
            yOrigin: bounds.y,
            duration: duration,
            easing: easing)
        
        addViewportJob(job)
    }
    
    /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
    /// This also refreshes the chart by calling setNeedsDisplay().
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func moveViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easingOption: ChartEasingOption)
    {
        moveViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
    }
    
    /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated.
    /// This also refreshes the chart by calling setNeedsDisplay().
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func moveViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval)
    {
        moveViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine)
    }
    
    /// This will move the center of the current viewport to the specified x-value and y-value.
    /// This also refreshes the chart by calling setNeedsDisplay().
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: - which axis should be used as a reference for the y-axis
    @objc open func centerViewTo(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency)
    {
        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
        let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX)
        
        let job = MoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: xValue - xInView / 2.0,
            yValue: yValue + yInView / 2.0,
            transformer: getTransformer(forAxis: axis),
            view: self)
        
        addViewportJob(job)
    }
    
    /// This will move the center of the current viewport to the specified x-value and y-value animated.
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func centerViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easing: ChartEasingFunctionBlock?)
    {
        let bounds = valueForTouchPoint(
            point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
            axis: axis)
        
        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
        let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX)
        
        let job = AnimatedMoveViewJob(
            viewPortHandler: viewPortHandler,
            xValue: xValue - xInView / 2.0,
            yValue: yValue + yInView / 2.0,
            transformer: getTransformer(forAxis: axis),
            view: self,
            xOrigin: bounds.x,
            yOrigin: bounds.y,
            duration: duration,
            easing: easing)
        
        addViewportJob(job)
    }
    
    /// This will move the center of the current viewport to the specified x-value and y-value animated.
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func centerViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval,
        easingOption: ChartEasingOption)
    {
        centerViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption))
    }
    
    /// This will move the center of the current viewport to the specified x-value and y-value animated.
    ///
    /// - Parameters:
    ///   - xValue:
    ///   - yValue:
    ///   - axis: which axis should be used as a reference for the y-axis
    ///   - duration: the duration of the animation in seconds
    ///   - easing:
    @objc open func centerViewToAnimated(
        xValue: Double,
        yValue: Double,
        axis: YAxis.AxisDependency,
        duration: TimeInterval)
    {
        centerViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine)
    }

    /// Sets custom offsets for the current `ChartViewPort` (the offsets on the sides of the actual chart window). Setting this will prevent the chart from automatically calculating it's offsets. Use `resetViewPortOffsets()` to undo this.
    /// ONLY USE THIS WHEN YOU KNOW WHAT YOU ARE DOING, else use `setExtraOffsets(...)`.
    @objc open func setViewPortOffsets(left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
    {
        _customViewPortEnabled = true
        
        if Thread.isMainThread
        {
            self._viewPortHandler.restrainViewPort(offsetLeft: left, offsetTop: top, offsetRight: right, offsetBottom: bottom)
            prepareOffsetMatrix()
            prepareValuePxMatrix()
        }
        else
        {
            DispatchQueue.main.async(execute: {
                self.setViewPortOffsets(left: left, top: top, right: right, bottom: bottom)
            })
        }
    }

    /// Resets all custom offsets set via `setViewPortOffsets(...)` method. Allows the chart to again calculate all offsets automatically.
    @objc open func resetViewPortOffsets()
    {
        _customViewPortEnabled = false
        calculateOffsets()
    }

    // MARK: - Accessors
    
    /// - Returns: The range of the specified axis.
    @objc open func getAxisRange(axis: YAxis.AxisDependency) -> Double
    {
        if axis == .left
        {
            return leftAxis.axisRange
        }
        else
        {
            return rightAxis.axisRange
        }
    }

    /// - Returns: The position (in pixels) the provided Entry has inside the chart view
    @objc open func getPosition(entry e: ChartDataEntry, axis: YAxis.AxisDependency) -> CGPoint
    {
        var vals = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y))

        getTransformer(forAxis: axis).pointValueToPixel(&vals)

        return vals
    }

    /// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling).
    @objc open var dragEnabled: Bool
    {
        get
        {
            return _dragXEnabled || _dragYEnabled
        }
        set
        {
            _dragYEnabled = newValue
            _dragXEnabled = newValue
        }
    }
    
    /// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling).
    @objc open var isDragEnabled: Bool
    {
        return dragEnabled
    }
    
    /// is dragging on the X axis enabled?
    @objc open var dragXEnabled: Bool
    {
        get
        {
            return _dragXEnabled
        }
        set
        {
            _dragXEnabled = newValue
        }
    }
    
    /// is dragging on the Y axis enabled?
    @objc open var dragYEnabled: Bool
    {
        get
        {
            return _dragYEnabled
        }
        set
        {
            _dragYEnabled = newValue
        }
    }
    
    /// is scaling enabled? (zooming in and out by gesture) for the chart (this does not affect dragging).
    @objc open func setScaleEnabled(_ enabled: Bool)
    {
        if _scaleXEnabled != enabled || _scaleYEnabled != enabled
        {
            _scaleXEnabled = enabled
            _scaleYEnabled = enabled
            #if !os(tvOS)
            _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
            #endif
        }
    }
    
    @objc open var scaleXEnabled: Bool
    {
        get
        {
            return _scaleXEnabled
        }
        set
        {
            if _scaleXEnabled != newValue
            {
                _scaleXEnabled = newValue
                #if !os(tvOS)
                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                #endif
            }
        }
    }
    
    @objc open var scaleYEnabled: Bool
    {
        get
        {
            return _scaleYEnabled
        }
        set
        {
            if _scaleYEnabled != newValue
            {
                _scaleYEnabled = newValue
                #if !os(tvOS)
                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                #endif
            }
        }
    }
    
    @objc open var isScaleXEnabled: Bool { return scaleXEnabled }
    @objc open var isScaleYEnabled: Bool { return scaleYEnabled }
    
    /// flag that indicates if double tap zoom is enabled or not
    @objc open var doubleTapToZoomEnabled: Bool
    {
        get
        {
            return _doubleTapToZoomEnabled
        }
        set
        {
            if _doubleTapToZoomEnabled != newValue
            {
                _doubleTapToZoomEnabled = newValue
                _doubleTapGestureRecognizer.isEnabled = _doubleTapToZoomEnabled
            }
        }
    }
    
    /// **default**: true
    /// `true` if zooming via double-tap is enabled `false` ifnot.
    @objc open var isDoubleTapToZoomEnabled: Bool
    {
        return doubleTapToZoomEnabled
    }
    
    /// flag that indicates if highlighting per dragging over a fully zoomed out chart is enabled
    @objc open var highlightPerDragEnabled = true
    
    /// If set to true, highlighting per dragging over a fully zoomed out chart is enabled
    /// You might want to disable this when using inside a `NSUIScrollView`
    /// 
    /// **default**: true
    @objc open var isHighlightPerDragEnabled: Bool
    {
        return highlightPerDragEnabled
    }
    
    /// **default**: true
    /// `true` if drawing the grid background is enabled, `false` ifnot.
    @objc open var isDrawGridBackgroundEnabled: Bool
    {
        return drawGridBackgroundEnabled
    }
    
    /// **default**: false
    /// `true` if drawing the borders rectangle is enabled, `false` ifnot.
    @objc open var isDrawBordersEnabled: Bool
    {
        return drawBordersEnabled
    }

    /// - Returns: The x and y values in the chart at the given touch point
    /// (encapsulated in a `CGPoint`). This method transforms pixel coordinates to
    /// coordinates / values in the chart. This is the opposite method to
    /// `getPixelsForValues(...)`.
    @objc open func valueForTouchPoint(point pt: CGPoint, axis: YAxis.AxisDependency) -> CGPoint
    {
        return getTransformer(forAxis: axis).valueForTouchPoint(pt)
    }

    /// Transforms the given chart values into pixels. This is the opposite
    /// method to `valueForTouchPoint(...)`.
    @objc open func pixelForValues(x: Double, y: Double, axis: YAxis.AxisDependency) -> CGPoint
    {
        return getTransformer(forAxis: axis).pixelForValues(x: x, y: y)
    }
    
    /// - Returns: The Entry object displayed at the touched position of the chart
    @objc open func getEntryByTouchPoint(point pt: CGPoint) -> ChartDataEntry!
    {
        if let h = getHighlightByTouchPoint(pt)
        {
            return _data!.entryForHighlight(h)
        }
        return nil
    }
    
    /// - Returns: The DataSet object displayed at the touched position of the chart
    @objc open func getDataSetByTouchPoint(point pt: CGPoint) -> IBarLineScatterCandleBubbleChartDataSet?
    {
        let h = getHighlightByTouchPoint(pt)
        if h !== nil
        {
            return _data?.getDataSetByIndex(h!.dataSetIndex) as? IBarLineScatterCandleBubbleChartDataSet
        }
        return nil
    }

    /// The current x-scale factor
    @objc open var scaleX: CGFloat
    {
        if _viewPortHandler === nil
        {
            return 1.0
        }
        return _viewPortHandler.scaleX
    }

    /// The current y-scale factor
    @objc open var scaleY: CGFloat
    {
        if _viewPortHandler === nil
        {
            return 1.0
        }
        return _viewPortHandler.scaleY
    }

    /// if the chart is fully zoomed out, return true
    @objc open var isFullyZoomedOut: Bool { return _viewPortHandler.isFullyZoomedOut }

    /// - Returns: The y-axis object to the corresponding AxisDependency. In the
    /// horizontal bar-chart, LEFT == top, RIGHT == BOTTOM
    @objc open func getAxis(_ axis: YAxis.AxisDependency) -> YAxis
    {
        if axis == .left
        {
            return leftAxis
        }
        else
        {
            return rightAxis
        }
    }
    
    /// flag that indicates if pinch-zoom is enabled. if true, both x and y axis can be scaled simultaneously with 2 fingers, if false, x and y axis can be scaled separately
    @objc open var pinchZoomEnabled: Bool
    {
        get
        {
            return _pinchZoomEnabled
        }
        set
        {
            if _pinchZoomEnabled != newValue
            {
                _pinchZoomEnabled = newValue
                #if !os(tvOS)
                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                #endif
            }
        }
    }

    /// **default**: false
    /// `true` if pinch-zoom is enabled, `false` ifnot
    @objc open var isPinchZoomEnabled: Bool { return pinchZoomEnabled }

    /// Set an offset in dp that allows the user to drag the chart over it's
    /// bounds on the x-axis.
    @objc open func setDragOffsetX(_ offset: CGFloat)
    {
        _viewPortHandler.setDragOffsetX(offset)
    }

    /// Set an offset in dp that allows the user to drag the chart over it's
    /// bounds on the y-axis.
    @objc open func setDragOffsetY(_ offset: CGFloat)
    {
        _viewPortHandler.setDragOffsetY(offset)
    }

    /// `true` if both drag offsets (x and y) are zero or smaller.
    @objc open var hasNoDragOffset: Bool { return _viewPortHandler.hasNoDragOffset }

    open override var chartYMax: Double
    {
        return max(leftAxis._axisMaximum, rightAxis._axisMaximum)
    }

    open override var chartYMin: Double
    {
        return min(leftAxis._axisMinimum, rightAxis._axisMinimum)
    }
    
    /// `true` if either the left or the right or both axes are inverted.
    @objc open var isAnyAxisInverted: Bool
    {
        return leftAxis.isInverted || rightAxis.isInverted
    }
    
    /// flag that indicates if auto scaling on the y axis is enabled.
    /// if yes, the y axis automatically adjusts to the min and max y values of the current x axis range whenever the viewport changes
    @objc open var autoScaleMinMaxEnabled: Bool
    {
        get { return _autoScaleMinMaxEnabled }
        set { _autoScaleMinMaxEnabled = newValue }
    }
    
    /// **default**: false
    /// `true` if auto scaling on the y axis is enabled.
    @objc open var isAutoScaleMinMaxEnabled : Bool { return autoScaleMinMaxEnabled }
    
    /// Sets a minimum width to the specified y axis.
    @objc open func setYAxisMinWidth(_ axis: YAxis.AxisDependency, width: CGFloat)
    {
        if axis == .left
        {
            leftAxis.minWidth = width
        }
        else
        {
            rightAxis.minWidth = width
        }
    }
    
    /// **default**: 0.0
    ///
    /// - Returns: The (custom) minimum width of the specified Y axis.
    @objc open func getYAxisMinWidth(_ axis: YAxis.AxisDependency) -> CGFloat
    {
        if axis == .left
        {
            return leftAxis.minWidth
        }
        else
        {
            return rightAxis.minWidth
        }
    }
    /// Sets a maximum width to the specified y axis.
    /// Zero (0.0) means there's no maximum width
    @objc open func setYAxisMaxWidth(_ axis: YAxis.AxisDependency, width: CGFloat)
    {
        if axis == .left
        {
            leftAxis.maxWidth = width
        }
        else
        {
            rightAxis.maxWidth = width
        }
    }
    
    /// Zero (0.0) means there's no maximum width
    ///
    /// **default**: 0.0 (no maximum specified)
    ///
    /// - Returns: The (custom) maximum width of the specified Y axis.
    @objc open func getYAxisMaxWidth(_ axis: YAxis.AxisDependency) -> CGFloat
    {
        if axis == .left
        {
            return leftAxis.maxWidth
        }
        else
        {
            return rightAxis.maxWidth
        }
    }

    /// - Returns the width of the specified y axis.
    @objc open func getYAxisWidth(_ axis: YAxis.AxisDependency) -> CGFloat
    {
        if axis == .left
        {
            return leftAxis.requiredSize().width
        }
        else
        {
            return rightAxis.requiredSize().width
        }
    }
    
    // MARK: - BarLineScatterCandleBubbleChartDataProvider
    
    /// - Returns: The Transformer class that contains all matrices and is
    /// responsible for transforming values into pixels on the screen and
    /// backwards.
    open func getTransformer(forAxis axis: YAxis.AxisDependency) -> Transformer
    {
        if axis == .left
        {
            return _leftAxisTransformer
        }
        else
        {
            return _rightAxisTransformer
        }
    }
    
    /// the number of maximum visible drawn values on the chart only active when `drawValuesEnabled` is enabled
    open override var maxVisibleCount: Int
    {
        get
        {
            return _maxVisibleCount
        }
        set
        {
            _maxVisibleCount = newValue
        }
    }
    
    open func isInverted(axis: YAxis.AxisDependency) -> Bool
    {
        return getAxis(axis).isInverted
    }
    
    /// The lowest x-index (value on the x-axis) that is still visible on he chart.
    open var lowestVisibleX: Double
    {
        var pt = CGPoint(
            x: viewPortHandler.contentLeft,
            y: viewPortHandler.contentBottom)
        
        getTransformer(forAxis: .left).pixelToValues(&pt)
        
        return max(xAxis._axisMinimum, Double(pt.x))
    }
    
    /// The highest x-index (value on the x-axis) that is still visible on the chart.
    open var highestVisibleX: Double
    {
        var pt = CGPoint(
            x: viewPortHandler.contentRight,
            y: viewPortHandler.contentBottom)
        
        getTransformer(forAxis: .left).pixelToValues(&pt)

        return min(xAxis._axisMaximum, Double(pt.x))
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/BubbleChartView.swift
================================================
//
//  BubbleChartView.swift
//  Charts
//
//  Bubble chart implementation:
//    Copyright 2015 Pierre-Marc Airoldi
//    Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

open class BubbleChartView: BarLineChartViewBase, BubbleChartDataProvider
{
    open override func initialize()
    {
        super.initialize()
        
        renderer = BubbleChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
    }
    
    // MARK: - BubbleChartDataProvider
    
    open var bubbleData: BubbleChartData? { return _data as? BubbleChartData }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/CandleStickChartView.swift
================================================
//
//  CandleStickChartView.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

/// Financial chart type that draws candle-sticks.
open class CandleStickChartView: BarLineChartViewBase, CandleChartDataProvider
{
    internal override func initialize()
    {
        super.initialize()
        
        renderer = CandleStickChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
        
        self.xAxis.spaceMin = 0.5
        self.xAxis.spaceMax = 0.5
    }
    
    // MARK: - CandleChartDataProvider
    
    open var candleData: CandleChartData?
    {
        return _data as? CandleChartData
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/ChartViewBase.swift
================================================
//
//  ChartViewBase.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//
//  Based on https://github.com/PhilJay/MPAndroidChart/commit/c42b880

import Foundation
import CoreGraphics

#if canImport(UIKit)
    import UIKit
#endif

#if canImport(Cocoa)
import Cocoa
#endif

@objc
public protocol ChartViewDelegate
{
    /// Called when a value has been selected inside the chart.
    ///
    /// - Parameters:
    ///   - entry: The selected Entry.
    ///   - highlight: The corresponding highlight object that contains information about the highlighted position such as dataSetIndex etc.
    @objc optional func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight)
    
    /// Called when a user stops panning between values on the chart
    @objc optional func chartViewDidEndPanning(_ chartView: ChartViewBase)
    
    // Called when nothing has been selected or an "un-select" has been made.
    @objc optional func chartValueNothingSelected(_ chartView: ChartViewBase)
    
    // Callbacks when the chart is scaled / zoomed via pinch zoom gesture.
    @objc optional func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat)
    
    // Callbacks when the chart is moved / translated via drag gesture.
    @objc optional func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat)

    // Callbacks when Animator stops animating
    @objc optional func chartView(_ chartView: ChartViewBase, animatorDidStop animator: Animator)
}

open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
{
    // MARK: - Properties
    
    /// - Returns: The object representing all x-labels, this method can be used to
    /// acquire the XAxis object and modify it (e.g. change the position of the
    /// labels)
    @objc open var xAxis: XAxis
    {
        return _xAxis
    }
    
    /// The default IValueFormatter that has been determined by the chart considering the provided minimum and maximum values.
    internal var _defaultValueFormatter: IValueFormatter? = DefaultValueFormatter(decimals: 0)
    
    /// object that holds all data that was originally set for the chart, before it was modified or any filtering algorithms had been applied
    internal var _data: ChartData?
    
    /// Flag that indicates if highlighting per tap (touch) is enabled
    private var _highlightPerTapEnabled = true
    
    /// If set to true, chart continues to scroll after touch up
    @objc open var dragDecelerationEnabled = true
    
    /// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
    /// 1 is an invalid value, and will be converted to 0.999 automatically.
    private var _dragDecelerationFrictionCoef: CGFloat = 0.9
    
    /// if true, units are drawn next to the values in the chart
    internal var _drawUnitInChart = false
    
    /// The object representing the labels on the x-axis
    internal var _xAxis: XAxis!
    
    /// The `Description` object of the chart.
    /// This should have been called just "description", but
    @objc open var chartDescription: Description?
        
    /// The legend object containing all data associated with the legend
    internal var _legend: Legend!
    
    /// delegate to receive chart events
    @objc open weak var delegate: ChartViewDelegate?
    
    /// text that is displayed when the chart is empty
    @objc open var noDataText = "No chart data available."
    
    /// Font to be used for the no data text.
    @objc open var noDataFont = NSUIFont.systemFont(ofSize: 12)
    
    /// color of the no data text
    @objc open var noDataTextColor: NSUIColor = .labelOrBlack

    /// alignment of the no data text
    @objc open var noDataTextAlignment: NSTextAlignment = .left

    internal var _legendRenderer: LegendRenderer!
    
    /// object responsible for rendering the data
    @objc open var renderer: DataRenderer?
    
    @objc open var highlighter: IHighlighter?
    
    /// object that manages the bounds and drawing constraints of the chart
    internal var _viewPortHandler: ViewPortHandler!
    
    /// object responsible for animations
    internal var _animator: Animator!
    
    /// flag that indicates if offsets calculation has already been done or not
    private var _offsetsCalculated = false
    
    /// array of Highlight objects that reference the highlighted slices in the chart
    internal var _indicesToHighlight = [Highlight]()
    
    /// `true` if drawing the marker is enabled when tapping on values
    /// (use the `marker` property to specify a marker)
    @objc open var drawMarkers = true
    
    /// - Returns: `true` if drawing the marker is enabled when tapping on values
    /// (use the `marker` property to specify a marker)
    @objc open var isDrawMarkersEnabled: Bool { return drawMarkers }
    
    /// The marker that is displayed when a value is clicked on the chart
    @objc open var marker: IMarker?
    
    private var _interceptTouchEvents = false
    
    /// An extra offset to be appended to the viewport's top
    @objc open var extraTopOffset: CGFloat = 0.0
    
    /// An extra offset to be appended to the viewport's right
    @objc open var extraRightOffset: CGFloat = 0.0
    
    /// An extra offset to be appended to the viewport's bottom
    @objc open var extraBottomOffset: CGFloat = 0.0
    
    /// An extra offset to be appended to the viewport's left
    @objc open var extraLeftOffset: CGFloat = 0.0
    
    @objc open func setExtraOffsets(left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
    {
        extraLeftOffset = left
        extraTopOffset = top
        extraRightOffset = right
        extraBottomOffset = bottom
    }
    
    // MARK: - Initializers
    
    public override init(frame: CGRect)
    {
        super.init(frame: frame)
        initialize()
    }
    
    public required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)
        initialize()
    }
    
    deinit
    {
        self.removeObserver(self, forKeyPath: "bounds")
        self.removeObserver(self, forKeyPath: "frame")
    }
    
    internal func initialize()
    {
        #if os(iOS)
        self.backgroundColor = NSUIColor.clear
        #endif

        _animator = Animator()
        _animator.delegate = self

        _viewPortHandler = ViewPortHandler(width: bounds.size.width, height: bounds.size.height)
        
        chartDescription = Description()
        
        _legend = Legend()
        _legendRenderer = LegendRenderer(viewPortHandler: _viewPortHandler, legend: _legend)
        
        _xAxis = XAxis()
        
        self.addObserver(self, forKeyPath: "bounds", options: .new, context: nil)
        self.addObserver(self, forKeyPath: "frame", options: .new, context: nil)
    }
    
    // MARK: - ChartViewBase
    
    /// The data for the chart
    open var data: ChartData?
    {
        get
        {
            return _data
        }
        set
        {
            _data = newValue
            _offsetsCalculated = false
            
            guard let _data = _data else
            {
                setNeedsDisplay()
                return
            }
            
            // calculate how many digits are needed
            setupDefaultFormatter(min: _data.getYMin(), max: _data.getYMax())
            
            for set in _data.dataSets
            {
                if set.needsFormatter || set.valueFormatter === _defaultValueFormatter
                {
                    set.valueFormatter = _defaultValueFormatter
                }
            }
            
            // let the chart know there is new data
            notifyDataSetChanged()
        }
    }
    
    /// Clears the chart from all data (sets it to null) and refreshes it (by calling setNeedsDisplay()).
    @objc open func clear()
    {
        _data = nil
        _offsetsCalculated = false
        _indicesToHighlight.removeAll()
        lastHighlighted = nil
    
        setNeedsDisplay()
    }
    
    /// Removes all DataSets (and thereby Entries) from the chart. Does not set the data object to nil. Also refreshes the chart by calling setNeedsDisplay().
    @objc open func clearValues()
    {
        _data?.clearValues()
        setNeedsDisplay()
    }

    /// - Returns: `true` if the chart is empty (meaning it's data object is either null or contains no entries).
    @objc open func isEmpty() -> Bool
    {
        guard let data = _data else { return true }

        if data.entryCount <= 0
        {
            return true
        }
        else
        {
            return false
        }
    }
    
    /// Lets the chart know its underlying data has changed and should perform all necessary recalculations.
    /// It is crucial that this method is called everytime data is changed dynamically. Not calling this method can lead to crashes or unexpected behaviour.
    @objc open func notifyDataSetChanged()
    {
        fatalError("notifyDataSetChanged() cannot be called on ChartViewBase")
    }
    
    /// Calculates the offsets of the chart to the border depending on the position of an eventual legend or depending on the length of the y-axis and x-axis labels and their position
    internal func calculateOffsets()
    {
        fatalError("calculateOffsets() cannot be called on ChartViewBase")
    }
    
    /// calcualtes the y-min and y-max value and the y-delta and x-delta value
    internal func calcMinMax()
    {
        fatalError("calcMinMax() cannot be called on ChartViewBase")
    }
    
    /// calculates the required number of digits for the values that might be drawn in the chart (if enabled), and creates the default value formatter
    internal func setupDefaultFormatter(min: Double, max: Double)
    {
        // check if a custom formatter is set or not
        var reference = Double(0.0)
        
        if let data = _data , data.entryCount >= 2
        {
            reference = fabs(max - min)
        }
        else
        {
            let absMin = fabs(min)
            let absMax = fabs(max)
            reference = absMin > absMax ? absMin : absMax
        }
        
    
        if _defaultValueFormatter is DefaultValueFormatter
        {
            // setup the formatter with a new number of digits
            let digits = reference.decimalPlaces
            
            (_defaultValueFormatter as? DefaultValueFormatter)?.decimals
             = digits
        }
    }
    
    open override func draw(_ rect: CGRect)
    {
        let optionalContext = NSUIGraphicsGetCurrentContext()
        guard let context = optionalContext else { return }
        
        let frame = self.bounds

        if _data === nil && noDataText.count > 0
        {
            context.saveGState()
            defer { context.restoreGState() }

            let paragraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
            paragraphStyle.minimumLineHeight = noDataFont.lineHeight
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = noDataTextAlignment

            ChartUtils.drawMultilineText(
                context: context,
                text: noDataText,
                point: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0),
                attributes:
                [.font: noDataFont,
                 .foregroundColor: noDataTextColor,
                 .paragraphStyle: paragraphStyle],
                constrainedToSize: self.bounds.size,
                anchor: CGPoint(x: 0.5, y: 0.5),
                angleRadians: 0.0)
            
            return
        }
        
        if !_offsetsCalculated
        {
            calculateOffsets()
            _offsetsCalculated = true
        }
    }
    
    /// Draws the description text in the bottom right corner of the chart (per default)
    internal func drawDescription(context: CGContext)
    {
        // check if description should be drawn
        guard
            let description = chartDescription,
            description.isEnabled,
            let descriptionText = description.text,
            descriptionText.count > 0
            else { return }
        
        let position = description.position ?? CGPoint(x: bounds.width - _viewPortHandler.offsetRight - description.xOffset,
                                                       y: bounds.height - _viewPortHandler.offsetBottom - description.yOffset - description.font.lineHeight)
        
        var attrs = [NSAttributedString.Key : Any]()
        
        attrs[NSAttributedString.Key.font] = description.font
        attrs[NSAttributedString.Key.foregroundColor] = description.textColor

        ChartUtils.drawText(
            context: context,
            text: descriptionText,
            point: position,
            align: description.textAlign,
            attributes: attrs)
    }
    
    // MARK: - Accessibility

    open override func accessibilityChildren() -> [Any]? {
        return renderer?.accessibleChartElements
    }

    // MARK: - Highlighting
    
    /// The array of currently highlighted values. This might an empty if nothing is highlighted.
    @objc open var highlighted: [Highlight]
    {
        return _indicesToHighlight
    }
    
    /// Set this to false to prevent values from being highlighted by tap gesture.
    /// Values can still be highlighted via drag or programmatically.
    /// **default**: true
    @objc open var highlightPerTapEnabled: Bool
    {
        get { return _highlightPerTapEnabled }
        set { _highlightPerTapEnabled = newValue }
    }
    
    /// `true` if values can be highlighted via tap gesture, `false` ifnot.
    @objc open var isHighLightPerTapEnabled: Bool
    {
        return highlightPerTapEnabled
    }
    
    /// Checks if the highlight array is null, has a length of zero or if the first object is null.
    ///
    /// - Returns: `true` if there are values to highlight, `false` ifthere are no values to highlight.
    @objc open func valuesToHighlight() -> Bool
    {
        return !_indicesToHighlight.isEmpty
    }

    /// Highlights the values at the given indices in the given DataSets. Provide
    /// null or an empty array to undo all highlighting. 
    /// This should be used to programmatically highlight values.
    /// This method *will not* call the delegate.
    @objc open func highlightValues(_ highs: [Highlight]?)
    {
        // set the indices to highlight
        _indicesToHighlight = highs ?? [Highlight]()
        
        if _indicesToHighlight.isEmpty
        {
            self.lastHighlighted = nil
        }
        else
        {
            self.lastHighlighted = _indicesToHighlight[0]
        }

        // redraw the chart
        setNeedsDisplay()
    }
    
    /// Highlights any y-value at the given x-value in the given DataSet.
    /// Provide -1 as the dataSetIndex to undo all highlighting.
    /// This method will call the delegate.
    ///
    /// - Parameters:
    ///   - x: The x-value to highlight
    ///   - dataSetIndex: The dataset index to search in
    ///   - dataIndex: The data index to search in (only used in CombinedChartView currently)
    @objc open func highlightValue(x: Double, dataSetIndex: Int, dataIndex: Int = -1)
    {
        highlightValue(x: x, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: true)
    }
    
    /// Highlights the value at the given x-value and y-value in the given DataSet.
    /// Provide -1 as the dataSetIndex to undo all highlighting.
    /// This method will call the delegate.
    ///
    /// - Parameters:
    ///   - x: The x-value to highlight
    ///   - y: The y-value to highlight. Supply `NaN` for "any"
    ///   - dataSetIndex: The dataset index to search in
    ///   - dataIndex: The data index to search in (only used in CombinedChartView currently)
    @objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, dataIndex: Int = -1)
    {
        highlightValue(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: true)
    }
    
    /// Highlights any y-value at the given x-value in the given DataSet.
    /// Provide -1 as the dataSetIndex to undo all highlighting.
    ///
    /// - Parameters:
    ///   - x: The x-value to highlight
    ///   - dataSetIndex: The dataset index to search in
    ///   - dataIndex: The data index to search in (only used in CombinedChartView currently)
    ///   - callDelegate: Should the delegate be called for this change
    @objc open func highlightValue(x: Double, dataSetIndex: Int, dataIndex: Int = -1, callDelegate: Bool)
    {
        highlightValue(x: x, y: .nan, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: callDelegate)
    }
    
    /// Highlights the value at the given x-value and y-value in the given DataSet.
    /// Provide -1 as the dataSetIndex to undo all highlighting.
    ///
    /// - Parameters:
    ///   - x: The x-value to highlight
    ///   - y: The y-value to highlight. Supply `NaN` for "any"
    ///   - dataSetIndex: The dataset index to search in
    ///   - dataIndex: The data index to search in (only used in CombinedChartView currently)
    ///   - callDelegate: Should the delegate be called for this change
    @objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, dataIndex: Int = -1, callDelegate: Bool)
    {
        guard let data = _data else
        {
            Swift.print("Value not highlighted because data is nil")
            return
        }
        
        if dataSetIndex < 0 || dataSetIndex >= data.dataSetCount
        {
            highlightValue(nil, callDelegate: callDelegate)
        }
        else
        {
            highlightValue(Highlight(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex), callDelegate: callDelegate)
        }
    }
    
    /// Highlights the values represented by the provided Highlight object
    /// This method *will not* call the delegate.
    ///
    /// - Parameters:
    ///   - highlight: contains information about which entry should be highlighted
    @objc open func highlightValue(_ highlight: Highlight?)
    {
        highlightValue(highlight, callDelegate: false)
    }

    /// Highlights the value selected by touch gesture.
    @objc open func highlightValue(_ highlight: Highlight?, callDelegate: Bool)
    {
        var entry: ChartDataEntry?
        var h = highlight
        
        if h == nil
        {
            self.lastHighlighted = nil
            _indicesToHighlight.removeAll(keepingCapacity: false)
        }
        else
        {
            // set the indices to highlight
            entry = _data?.entryForHighlight(h!)
            if entry == nil
            {
                h = nil
                _indicesToHighlight.removeAll(keepingCapacity: false)
            }
            else
            {
                _indicesToHighlight = [h!]
            }
        }
        
        if callDelegate, let delegate = delegate
        {
            if let h = h
            {
                // notify the listener
                delegate.chartValueSelected?(self, entry: entry!, highlight: h)
            }
            else
            {
                delegate.chartValueNothingSelected?(self)
            }
        }
        
        // redraw the chart
        setNeedsDisplay()
    }
    
    /// - Returns: The Highlight object (contains x-index and DataSet index) of the
    /// selected value at the given touch point inside the Line-, Scatter-, or
    /// CandleStick-Chart.
    @objc open func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
    {
        if _data === nil
        {
            Swift.print("Can't select by touch. No data set.")
            return nil
        }
        
        return self.highlighter?.getHighlight(x: pt.x, y: pt.y)
    }

    /// The last value that was highlighted via touch.
    @objc open var lastHighlighted: Highlight?
  
    // MARK: - Markers

    /// draws all MarkerViews on the highlighted positions
    internal func drawMarkers(context: CGContext)
    {
        // if there is no marker view or drawing marker is disabled
        guard
            let marker = marker
            , isDrawMarkersEnabled &&
                valuesToHighlight()
            else { return }
        
        for i in 0 ..< _indicesToHighlight.count
        {
            let highlight = _indicesToHighlight[i]
            
            guard let
                set = data?.getDataSetByIndex(highlight.dataSetIndex),
                let e = _data?.entryForHighlight(highlight)
                else { continue }
            
            let entryIndex = set.entryIndex(entry: e)
            if entryIndex > Int(Double(set.entryCount) * _animator.phaseX)
            {
                continue
            }

            let pos = getMarkerPosition(highlight: highlight)

            // check bounds
            if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y)
            {
                continue
            }

            // callbacks to update the content
            marker.refreshContent(entry: e, highlight: highlight)
            
            // draw the marker
            marker.draw(context: context, point: pos)
        }
    }
    
    /// - Returns: The actual position in pixels of the MarkerView for the given Entry in the given DataSet.
    @objc open func getMarkerPosition(highlight: Highlight) -> CGPoint
    {
        return CGPoint(x: highlight.drawX, y: highlight.drawY)
    }
    
    // MARK: - Animation
    
    /// The animator responsible for animating chart values.
    @objc open var chartAnimator: Animator!
    {
        return _animator
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingX: an easing function for the animation on the x axis
    ///   - easingY: an easing function for the animation on the y axis
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
    {
        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY)
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOptionX: the easing function for the animation on the x axis
    ///   - easingOptionY: the easing function for the animation on the y axis
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
    {
        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY)
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easing: an easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing)
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOption: ChartEasingOption)
    {
        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption)
    }
    
    /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - yAxisDuration: duration for animating the y axis
    @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval)
    {
        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration)
    }
    
    /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - easing: an easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        _animator.animate(xAxisDuration: xAxisDuration, easing: easing)
    }
    
    /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(xAxisDuration: TimeInterval, easingOption: ChartEasingOption)
    {
        _animator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption)
    }
    
    /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - xAxisDuration: duration for animating the x axis
    @objc open func animate(xAxisDuration: TimeInterval)
    {
        _animator.animate(xAxisDuration: xAxisDuration)
    }
    
    /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easing: an easing function for the animation
    @objc open func animate(yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
    {
        _animator.animate(yAxisDuration: yAxisDuration, easing: easing)
    }
    
    /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - yAxisDuration: duration for animating the y axis
    ///   - easingOption: the easing function for the animation
    @objc open func animate(yAxisDuration: TimeInterval, easingOption: ChartEasingOption)
    {
        _animator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption)
    }
    
    /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
    /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
    ///
    /// - Parameters:
    ///   - yAxisDuration: duration for animating the y axis
    @objc open func animate(yAxisDuration: TimeInterval)
    {
        _animator.animate(yAxisDuration: yAxisDuration)
    }
    
    // MARK: - Accessors

    /// The current y-max value across all DataSets
    open var chartYMax: Double
    {
        return _data?.yMax ?? 0.0
    }

    /// The current y-min value across all DataSets
    open var chartYMin: Double
    {
        return _data?.yMin ?? 0.0
    }
    
    open var chartXMax: Double
    {
        return _xAxis._axisMaximum
    }
    
    open var chartXMin: Double
    {
        return _xAxis._axisMinimum
    }
    
    open var xRange: Double
    {
        return _xAxis.axisRange
    }
    
    /// - Note: (Equivalent of getCenter() in MPAndroidChart, as center is already a standard in iOS that returns the center point relative to superview, and MPAndroidChart returns relative to self)*
    /// The center point of the chart (the whole View) in pixels.
    @objc open var midPoint: CGPoint
    {
        let bounds = self.bounds
        return CGPoint(x: bounds.origin.x + bounds.size.width / 2.0, y: bounds.origin.y + bounds.size.height / 2.0)
    }
    
    /// The center of the chart taking offsets under consideration. (returns the center of the content rectangle)
    open var centerOffsets: CGPoint
    {
        return _viewPortHandler.contentCenter
    }
    
    /// The Legend object of the chart. This method can be used to get an instance of the legend in order to customize the automatically generated Legend.
    @objc open var legend: Legend
    {
        return _legend
    }
    
    /// The renderer object responsible for rendering / drawing the Legend.
    @objc open var legendRenderer: LegendRenderer!
    {
        return _legendRenderer
    }
    
    /// The rectangle that defines the borders of the chart-value surface (into which the actual values are drawn).
    @objc open var contentRect: CGRect
    {
        return _viewPortHandler.contentRect
    }
    
    /// - Returns: The ViewPortHandler of the chart that is responsible for the
    /// content area of the chart and its offsets and dimensions.
    @objc open var viewPortHandler: ViewPortHandler!
    {
        return _viewPortHandler
    }
    
    /// - Returns: The bitmap that represents the chart.
    @objc open func getChartImage(transparent: Bool) -> NSUIImage?
    {
        NSUIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque || !transparent, NSUIScreen.nsuiMain?.nsuiScale ?? 1.0)
        
        guard let context = NSUIGraphicsGetCurrentContext()
            else { return nil }
        
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
        
        if isOpaque || !transparent
        {
            // Background color may be partially transparent, we must fill with white if we want to output an opaque image
            context.setFillColor(NSUIColor.white.cgColor)
            context.fill(rect)
            
            if let backgroundColor = self.backgroundColor
            {
                context.setFillColor(backgroundColor.cgColor)
                context.fill(rect)
            }
        }
        
        nsuiLayer?.render(in: context)
        
        let image = NSUIGraphicsGetImageFromCurrentImageContext()
        
        NSUIGraphicsEndImageContext()
        
        return image
    }
    
    public enum ImageFormat
    {
        case jpeg
        case png
    }
    
    /// Saves the current chart state with the given name to the given path on
    /// the sdcard leaving the path empty "" will put the saved file directly on
    /// the SD card chart is saved as a PNG image, example:
    /// saveToPath("myfilename", "foldername1/foldername2")
    ///
    /// - Parameters:
    ///   - to: path to the image to save
    ///   - format: the format to save
    ///   - compressionQuality: compression quality for lossless formats (JPEG)
    /// - Returns: `true` if the image was saved successfully
    open func save(to path: String, format: ImageFormat, compressionQuality: Double) -> Bool
    {
        guard let image = getChartImage(transparent: format != .jpeg) else { return false }
        
        let imageData: Data?
        switch (format)
        {
        case .png: imageData = NSUIImagePNGRepresentation(image)
        case .jpeg: imageData = NSUIImageJPEGRepresentation(image, CGFloat(compressionQuality))
        }
        
        guard let data = imageData else { return false }
        
        do
        {
            try data.write(to: URL(fileURLWithPath: path), options: .atomic)
        }
        catch
        {
            return false
        }
        
        return true
    }
    
    internal var _viewportJobs = [ViewPortJob]()
    
    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
    {
        if keyPath == "bounds" || keyPath == "frame"
        {
            let bounds = self.bounds
            
            if (_viewPortHandler !== nil &&
                (bounds.size.width != _viewPortHandler.chartWidth ||
                bounds.size.height != _viewPortHandler.chartHeight))
            {
                _viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
                
                // This may cause the chart view to mutate properties affecting the view port -- lets do this
                // before we try to run any pending jobs on the view port itself
                notifyDataSetChanged()

                // Finish any pending viewport changes
                while (!_viewportJobs.isEmpty)
                {
                    let job = _viewportJobs.remove(at: 0)
                    job.doJob()
                }
            }
        }
    }
    
    @objc open func removeViewportJob(_ job: ViewPortJob)
    {
        if let index = _viewportJobs.firstIndex(where: { $0 === job })
        {
            _viewportJobs.remove(at: index)
        }
    }
    
    @objc open func clearAllViewportJobs()
    {
        _viewportJobs.removeAll(keepingCapacity: false)
    }
    
    @objc open func addViewportJob(_ job: ViewPortJob)
    {
        if _viewPortHandler.hasChartDimens
        {
            job.doJob()
        }
        else
        {
            _viewportJobs.append(job)
        }
    }
    
    /// **default**: true
    /// `true` if chart continues to scroll after touch up, `false` ifnot.
    @objc open var isDragDecelerationEnabled: Bool
        {
            return dragDecelerationEnabled
    }
    
    /// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
    /// 1 is an invalid value, and will be converted to 0.999 automatically.
    /// 
    /// **default**: true
    @objc open var dragDecelerationFrictionCoef: CGFloat
    {
        get
        {
            return _dragDecelerationFrictionCoef
        }
        set
        {
            var val = newValue
            if val < 0.0
            {
                val = 0.0
            }
            if val >= 1.0
            {
                val = 0.999
            }
            
            _dragDecelerationFrictionCoef = val
        }
    }
    
    /// The maximum distance in screen pixels away from an entry causing it to highlight.
    /// **default**: 500.0
    open var maxHighlightDistance: CGFloat = 500.0
    
    /// the number of maximum visible drawn values on the chart only active when `drawValuesEnabled` is enabled
    open var maxVisibleCount: Int
    {
        return Int(INT_MAX)
    }
    
    // MARK: - AnimatorDelegate
    
    open func animatorUpdated(_ chartAnimator: Animator)
    {
        setNeedsDisplay()
    }
    
    open func animatorStopped(_ chartAnimator: Animator)
    {
        delegate?.chartView?(self, animatorDidStop: chartAnimator)
    }
    
    // MARK: - Touches
    
    open override func nsuiTouchesBegan(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
    {
        if !_interceptTouchEvents
        {
            super.nsuiTouchesBegan(touches, withEvent: event)
        }
    }
    
    open override func nsuiTouchesMoved(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
    {
        if !_interceptTouchEvents
        {
            super.nsuiTouchesMoved(touches, withEvent: event)
        }
    }
    
    open override func nsuiTouchesEnded(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
    {
        if !_interceptTouchEvents
        {
            super.nsuiTouchesEnded(touches, withEvent: event)
        }
    }
    
    open override func nsuiTouchesCancelled(_ touches: Set<NSUITouch>?, withEvent event: NSUIEvent?)
    {
        if !_interceptTouchEvents
        {
            super.nsuiTouchesCancelled(touches, withEvent: event)
        }
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/CombinedChartView.swift
================================================
//
//  CombinedChartView.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

/// This chart class allows the combination of lines, bars, scatter and candle data all displayed in one chart area.
open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
{
    /// the fill-formatter used for determining the position of the fill-line
    internal var _fillFormatter: IFillFormatter!
    
    /// enum that allows to specify the order in which the different data objects for the combined-chart are drawn
    @objc(CombinedChartDrawOrder)
    public enum DrawOrder: Int
    {
        case bar
        case bubble
        case line
        case candle
        case scatter
    }
    
    open override func initialize()
    {
        super.initialize()
        
        self.highlighter = CombinedHighlighter(chart: self, barDataProvider: self)
        
        // Old default behaviour
        self.highlightFullBarEnabled = true
        
        _fillFormatter = DefaultFillFormatter()
        
        renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
    }
    
    open override var data: ChartData?
    {
        get
        {
            return super.data
        }
        set
        {
            super.data = newValue
            
            self.highlighter = CombinedHighlighter(chart: self, barDataProvider: self)
            
            (renderer as? CombinedChartRenderer)?.createRenderers()
            renderer?.initBuffers()
        }
    }
    
    @objc open var fillFormatter: IFillFormatter
    {
        get
        {
            return _fillFormatter
        }
        set
        {
            _fillFormatter = newValue
            if _fillFormatter == nil
            {
                _fillFormatter = DefaultFillFormatter()
            }
        }
    }
    
    /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the CombinedChart.
    open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
    {
        if _data === nil
        {
            Swift.print("Can't select by touch. No data set.")
            return nil
        }
        
        guard let h = self.highlighter?.getHighlight(x: pt.x, y: pt.y)
            else { return nil }
        
        if !isHighlightFullBarEnabled { return h }
        
        // For isHighlightFullBarEnabled, remove stackIndex
        return Highlight(
            x: h.x, y: h.y,
            xPx: h.xPx, yPx: h.yPx,
            dataIndex: h.dataIndex,
            dataSetIndex: h.dataSetIndex,
            stackIndex: -1,
            axis: h.axis)
    }
    
    // MARK: - CombinedChartDataProvider
    
    open var combinedData: CombinedChartData?
    {
        get
        {
            return _data as? CombinedChartData
        }
    }
    
    // MARK: - LineChartDataProvider
    
    open var lineData: LineChartData?
    {
        get
        {
            return combinedData?.lineData
        }
    }
    
    // MARK: - BarChartDataProvider
    
    open var barData: BarChartData?
    {
        get
        {
            return combinedData?.barData
        }
    }
    
    // MARK: - ScatterChartDataProvider
    
    open var scatterData: ScatterChartData?
    {
        get
        {
            return combinedData?.scatterData
        }
    }
    
    // MARK: - CandleChartDataProvider
    
    open var candleData: CandleChartData?
    {
        get
        {
            return combinedData?.candleData
        }
    }
    
    // MARK: - BubbleChartDataProvider
    
    open var bubbleData: BubbleChartData?
    {
        get
        {
            return combinedData?.bubbleData
        }
    }
    
    // MARK: - Accessors
    
    /// if set to true, all values are drawn above their bars, instead of below their top
    @objc open var drawValueAboveBarEnabled: Bool
        {
        get { return (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled }
        set { (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled = newValue }
    }
    
    /// if set to true, a grey area is drawn behind each bar that indicates the maximum value
    @objc open var drawBarShadowEnabled: Bool
    {
        get { return (renderer as! CombinedChartRenderer).drawBarShadowEnabled }
        set { (renderer as! CombinedChartRenderer).drawBarShadowEnabled = newValue }
    }
    
    /// `true` if drawing values above bars is enabled, `false` ifnot
    open var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled }
    
    /// `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot
    open var isDrawBarShadowEnabled: Bool { return (renderer as! CombinedChartRenderer).drawBarShadowEnabled }
    
    /// the order in which the provided data objects should be drawn.
    /// The earlier you place them in the provided array, the further they will be in the background. 
    /// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
    @objc open var drawOrder: [Int]
    {
        get
        {
            return (renderer as! CombinedChartRenderer).drawOrder.map { $0.rawValue }
        }
        set
        {
            (renderer as! CombinedChartRenderer).drawOrder = newValue.map { DrawOrder(rawValue: $0)! }
        }
    }
    
    /// Set this to `true` to make the highlight operation full-bar oriented, `false` to make it highlight single values
    @objc open var highlightFullBarEnabled: Bool = false
    
    /// `true` the highlight is be full-bar oriented, `false` ifsingle-value
    open var isHighlightFullBarEnabled: Bool { return highlightFullBarEnabled }
    
    // MARK: - ChartViewBase
    
    /// draws all MarkerViews on the highlighted positions
    override func drawMarkers(context: CGContext)
    {
        guard
            let marker = marker, 
            isDrawMarkersEnabled && valuesToHighlight()
            else { return }
        
        for i in 0 ..< _indicesToHighlight.count
        {
            let highlight = _indicesToHighlight[i]
            
            guard 
                let set = combinedData?.getDataSetByHighlight(highlight),
                let e = _data?.entryForHighlight(highlight)
                else { continue }
            
            let entryIndex = set.entryIndex(entry: e)
            if entryIndex > Int(Double(set.entryCount) * _animator.phaseX)
            {
                continue
            }
            
            let pos = getMarkerPosition(highlight: highlight)
            
            // check bounds
            if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y)
            {
                continue
            }
            
            // callbacks to update the content
            marker.refreshContent(entry: e, highlight: highlight)
            
            // draw the marker
            marker.draw(context: context, point: pos)
        }
    }
}


================================================
FILE: mac/Pods/Charts/Source/Charts/Charts/HorizontalBarChartView.swift
================================================
//
//  HorizontalBarChartView.swift
//  Charts
//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/Charts
//

import Foundation
import CoreGraphics

/// BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched.
open class HorizontalBarChartView: BarChartView
{
    internal override func initialize()
    {
        super.initialize()
        
        _leftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
        _rightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
        
        renderer = HorizontalBarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
        leftYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer)
        rightYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer)
        xAxisRenderer = XAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
        
        self.highlighter = HorizontalBarHighlighter(chart: self)
    }
    
    internal override func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat)
    {
        guard
            let legend = _legend,
            legend.isEnabled,
            !legend.drawInside
        else { return }
        
        // setup offsets for legend
        switch legend.orientation
        {
        case .vertical:
            switch legend.horizontalAlignment
            {
            case .left:
                offsetLeft += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                
            case .right:
                offsetRight += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                
            case .center:
                
                switch legend.verticalAlignment
                {
                case .top:
                    offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                    
                case .bottom:
                    offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                    
                default:
                    break
                }
            }
            
        case .horizontal:
            switch legend.verticalAlignment
            {
            case .top:
                offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                
                // left axis equals the top x-axis in a horizontal chart
                if leftAxis.isEnabled && leftAxis.isDrawLabelsEnabled
                {
                    offsetTop += leftAxis.getRequiredHeightSpace()
                }
                
            case .bottom:
                offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset

                // right axis equals the bottom x-axis in a horizontal chart
                if rightAxis.isEnabled && rightAxis.isDrawLabelsEnabled
                {
                    offsetBottom += rightAxis.getRequiredHeightSpace()
                }
            default:
                break
            }
        }
    }
    
    internal override func calculateOffsets()
    {
        var offsetLeft: CGFloat = 0.0,
        offsetRight: CGFloat = 0.0,
        offsetTop: CGFloat = 0.0,
        offsetBottom: CGFloat = 0.0
        
        calculateLegendOffsets(offsetLeft: &offsetLeft,
                               offsetTop: &offsetTop,
                               offsetRight: &offsetRight,
                               offsetBottom: &offsetBottom)
        
        // offsets for y-labels
        if leftAxis.needsOffset
        {
            offsetTop += leftAxis.getRequiredHeightSpace()
        }
        
        if rightAxis.needsOffset
        {
            offsetBottom += rightAxis.getRequiredHeightSpace()
        }
        
        let xlabelwidth = _xAxis.labelRotatedWidth
        
        if _xAxis.isEnabled
        {
            // offsets for x-labels
            if _xAxis.labelPosition == .bottom
            {
                offsetLeft += xlabelwidth
            }
            else if _xAxis.labelPosition == .top
            {
                offsetRight += xlabelwidth
            }
            else if _xAxis.labelPosition == .bothSided
            {
                offsetLeft += xlabelwidth
                offsetRight += xlabelwidth
            }
        }
        
        offsetTop += self.extraTopOffset
        offsetRight += self.extraRightOffset
        offsetBottom += self.extraBottomOffset
        offsetLeft += self.extraLeftOffset

        _viewPortHandler.restrainViewPort(
            offsetLeft: max(self.minOffset, offsetLeft),
            offsetTop: max(self.minOffset, offsetTop),
            offsetRight: max(self.minOffset, offsetRight),
            offsetBottom: max(self.minOffset, offsetBottom))
        
        prepareOffsetMatrix()
        prepareValuePxMatrix()
    }
    
    internal override func prepareValuePxMatrix()
    {
        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: rightAxis._axisMinimum, deltaX: CGFloat(rightAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
        _leftAxisTransformer.prepareMatrixValuePx(chartXMin: leftAxis._axisMinimum, deltaX: CGFloat(leftAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
    }
    
    open override func getMarkerPosition(highlight: Highlight) -> CGPoint
    {
        return CGPoint(x: highlight.drawY, y: highlight.drawX)
    }
    
    open override func getBarBounds(entry e: BarChartDataEntry) -> CGRect
    {
        guard
            let data = _data as? BarChartData,
            let set = data.getDataSetForEntry(e) as? IBarChartDataSet
            else { return CGRect.null }
        
        let y = e.y
        let x = e.x
        
        let barWidth = data.barWidth
        
        let top = x - 0.5 + barWidth / 2.0
        let bottom = x + 0.5 - barWidth / 2.0
        let left = y >= 0.0 ? y : 0.0
        let right = y
Download .txt
gitextract_yvxi4i9t/

├── .github/
│   └── workflows/
│       ├── build_app.yml
│       └── make-test.yml
├── .gitignore
├── Makefile
├── README.md
├── go.mod
├── go.sum
├── keyrace.c
├── mac/
│   ├── Podfile
│   ├── Pods/
│   │   ├── Charts/
│   │   │   ├── LICENSE
│   │   │   ├── README.md
│   │   │   └── Source/
│   │   │       └── Charts/
│   │   │           ├── Animation/
│   │   │           │   ├── Animator.swift
│   │   │           │   └── ChartAnimationEasing.swift
│   │   │           ├── Charts/
│   │   │           │   ├── BarChartView.swift
│   │   │           │   ├── BarLineChartViewBase.swift
│   │   │           │   ├── BubbleChartView.swift
│   │   │           │   ├── CandleStickChartView.swift
│   │   │           │   ├── ChartViewBase.swift
│   │   │           │   ├── CombinedChartView.swift
│   │   │           │   ├── HorizontalBarChartView.swift
│   │   │           │   ├── LineChartView.swift
│   │   │           │   ├── PieChartView.swift
│   │   │           │   ├── PieRadarChartViewBase.swift
│   │   │           │   ├── RadarChartView.swift
│   │   │           │   └── ScatterChartView.swift
│   │   │           ├── Components/
│   │   │           │   ├── AxisBase.swift
│   │   │           │   ├── ChartLimitLine.swift
│   │   │           │   ├── ComponentBase.swift
│   │   │           │   ├── Description.swift
│   │   │           │   ├── IMarker.swift
│   │   │           │   ├── Legend.swift
│   │   │           │   ├── LegendEntry.swift
│   │   │           │   ├── MarkerImage.swift
│   │   │           │   ├── MarkerView.swift
│   │   │           │   ├── XAxis.swift
│   │   │           │   └── YAxis.swift
│   │   │           ├── Data/
│   │   │           │   ├── Implementations/
│   │   │           │   │   ├── ChartBaseDataSet.swift
│   │   │           │   │   └── Standard/
│   │   │           │   │       ├── BarChartData.swift
│   │   │           │   │       ├── BarChartDataEntry.swift
│   │   │           │   │       ├── BarChartDataSet.swift
│   │   │           │   │       ├── BarLineScatterCandleBubbleChartData.swift
│   │   │           │   │       ├── BarLineScatterCandleBubbleChartDataSet.swift
│   │   │           │   │       ├── BubbleChartData.swift
│   │   │           │   │       ├── BubbleChartDataEntry.swift
│   │   │           │   │       ├── BubbleChartDataSet.swift
│   │   │           │   │       ├── CandleChartData.swift
│   │   │           │   │       ├── CandleChartDataEntry.swift
│   │   │           │   │       ├── CandleChartDataSet.swift
│   │   │           │   │       ├── ChartData.swift
│   │   │           │   │       ├── ChartDataEntry.swift
│   │   │           │   │       ├── ChartDataEntryBase.swift
│   │   │           │   │       ├── ChartDataSet.swift
│   │   │           │   │       ├── CombinedChartData.swift
│   │   │           │   │       ├── LineChartData.swift
│   │   │           │   │       ├── LineChartDataSet.swift
│   │   │           │   │       ├── LineRadarChartDataSet.swift
│   │   │           │   │       ├── LineScatterCandleRadarChartDataSet.swift
│   │   │           │   │       ├── PieChartData.swift
│   │   │           │   │       ├── PieChartDataEntry.swift
│   │   │           │   │       ├── PieChartDataSet.swift
│   │   │           │   │       ├── RadarChartData.swift
│   │   │           │   │       ├── RadarChartDataEntry.swift
│   │   │           │   │       ├── RadarChartDataSet.swift
│   │   │           │   │       ├── ScatterChartData.swift
│   │   │           │   │       └── ScatterChartDataSet.swift
│   │   │           │   └── Interfaces/
│   │   │           │       ├── IBarChartDataSet.swift
│   │   │           │       ├── IBarLineScatterCandleBubbleChartDataSet.swift
│   │   │           │       ├── IBubbleChartDataSet.swift
│   │   │           │       ├── ICandleChartDataSet.swift
│   │   │           │       ├── IChartDataSet.swift
│   │   │           │       ├── ILineChartDataSet.swift
│   │   │           │       ├── ILineRadarChartDataSet.swift
│   │   │           │       ├── ILineScatterCandleRadarChartDataSet.swift
│   │   │           │       ├── IPieChartDataSet.swift
│   │   │           │       ├── IRadarChartDataSet.swift
│   │   │           │       └── IScatterChartDataSet.swift
│   │   │           ├── Filters/
│   │   │           │   ├── DataApproximator+N.swift
│   │   │           │   └── DataApproximator.swift
│   │   │           ├── Formatters/
│   │   │           │   ├── DefaultAxisValueFormatter.swift
│   │   │           │   ├── DefaultFillFormatter.swift
│   │   │           │   ├── DefaultValueFormatter.swift
│   │   │           │   ├── IAxisValueFormatter.swift
│   │   │           │   ├── IFillFormatter.swift
│   │   │           │   ├── IValueFormatter.swift
│   │   │           │   └── IndexAxisValueFormatter.swift
│   │   │           ├── Highlight/
│   │   │           │   ├── BarHighlighter.swift
│   │   │           │   ├── ChartHighlighter.swift
│   │   │           │   ├── CombinedHighlighter.swift
│   │   │           │   ├── Highlight.swift
│   │   │           │   ├── HorizontalBarHighlighter.swift
│   │   │           │   ├── IHighlighter.swift
│   │   │           │   ├── PieHighlighter.swift
│   │   │           │   ├── PieRadarHighlighter.swift
│   │   │           │   ├── RadarHighlighter.swift
│   │   │           │   └── Range.swift
│   │   │           ├── Interfaces/
│   │   │           │   ├── BarChartDataProvider.swift
│   │   │           │   ├── BarLineScatterCandleBubbleChartDataProvider.swift
│   │   │           │   ├── BubbleChartDataProvider.swift
│   │   │           │   ├── CandleChartDataProvider.swift
│   │   │           │   ├── ChartDataProvider.swift
│   │   │           │   ├── CombinedChartDataProvider.swift
│   │   │           │   ├── LineChartDataProvider.swift
│   │   │           │   └── ScatterChartDataProvider.swift
│   │   │           ├── Jobs/
│   │   │           │   ├── AnimatedMoveViewJob.swift
│   │   │           │   ├── AnimatedViewPortJob.swift
│   │   │           │   ├── AnimatedZoomViewJob.swift
│   │   │           │   ├── MoveViewJob.swift
│   │   │           │   ├── ViewPortJob.swift
│   │   │           │   └── ZoomViewJob.swift
│   │   │           ├── Renderers/
│   │   │           │   ├── AxisRendererBase.swift
│   │   │           │   ├── BarChartRenderer.swift
│   │   │           │   ├── BarLineScatterCandleBubbleRenderer.swift
│   │   │           │   ├── BubbleChartRenderer.swift
│   │   │           │   ├── CandleStickChartRenderer.swift
│   │   │           │   ├── ChartDataRendererBase.swift
│   │   │           │   ├── CombinedChartRenderer.swift
│   │   │           │   ├── HorizontalBarChartRenderer.swift
│   │   │           │   ├── LegendRenderer.swift
│   │   │           │   ├── LineChartRenderer.swift
│   │   │           │   ├── LineRadarRenderer.swift
│   │   │           │   ├── LineScatterCandleRadarRenderer.swift
│   │   │           │   ├── PieChartRenderer.swift
│   │   │           │   ├── RadarChartRenderer.swift
│   │   │           │   ├── Renderer.swift
│   │   │           │   ├── Scatter/
│   │   │           │   │   ├── ChevronDownShapeRenderer.swift
│   │   │           │   │   ├── ChevronUpShapeRenderer.swift
│   │   │           │   │   ├── CircleShapeRenderer.swift
│   │   │           │   │   ├── CrossShapeRenderer.swift
│   │   │           │   │   ├── IShapeRenderer.swift
│   │   │           │   │   ├── SquareShapeRenderer.swift
│   │   │           │   │   ├── TriangleShapeRenderer.swift
│   │   │           │   │   └── XShapeRenderer.swift
│   │   │           │   ├── ScatterChartRenderer.swift
│   │   │           │   ├── XAxisRenderer.swift
│   │   │           │   ├── XAxisRendererHorizontalBarChart.swift
│   │   │           │   ├── XAxisRendererRadarChart.swift
│   │   │           │   ├── YAxisRenderer.swift
│   │   │           │   ├── YAxisRendererHorizontalBarChart.swift
│   │   │           │   └── YAxisRendererRadarChart.swift
│   │   │           └── Utils/
│   │   │               ├── ChartColorTemplates.swift
│   │   │               ├── ChartUtils.swift
│   │   │               ├── Fill.swift
│   │   │               ├── Platform+Accessibility.swift
│   │   │               ├── Platform+Color.swift
│   │   │               ├── Platform+Gestures.swift
│   │   │               ├── Platform+Graphics.swift
│   │   │               ├── Platform+Touch Handling.swift
│   │   │               ├── Platform.swift
│   │   │               ├── Transformer.swift
│   │   │               ├── TransformerHorizontalBarChart.swift
│   │   │               └── ViewPortHandler.swift
│   │   ├── Pods.xcodeproj/
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata/
│   │   │       └── xcschemes/
│   │   │           ├── Charts.xcscheme
│   │   │           └── Pods-keyrace-mac.xcscheme
│   │   └── Target Support Files/
│   │       ├── Charts/
│   │       │   ├── Charts-Info.plist
│   │       │   ├── Charts-dummy.m
│   │       │   ├── Charts-prefix.pch
│   │       │   ├── Charts-umbrella.h
│   │       │   ├── Charts.debug.xcconfig
│   │       │   ├── Charts.modulemap
│   │       │   └── Charts.release.xcconfig
│   │       └── Pods-keyrace-mac/
│   │           ├── Pods-keyrace-mac-Info.plist
│   │           ├── Pods-keyrace-mac-acknowledgements.markdown
│   │           ├── Pods-keyrace-mac-acknowledgements.plist
│   │           ├── Pods-keyrace-mac-dummy.m
│   │           ├── Pods-keyrace-mac-frameworks-Debug-input-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Debug-output-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Release-input-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks-Release-output-files.xcfilelist
│   │           ├── Pods-keyrace-mac-frameworks.sh
│   │           ├── Pods-keyrace-mac-umbrella.h
│   │           ├── Pods-keyrace-mac.debug.xcconfig
│   │           ├── Pods-keyrace-mac.modulemap
│   │           └── Pods-keyrace-mac.release.xcconfig
│   ├── keyrace-mac/
│   │   ├── AppDelegate.swift
│   │   ├── Assets.xcassets/
│   │   │   ├── AccentColor.colorset/
│   │   │   │   └── Contents.json
│   │   │   ├── AppIcon.appiconset/
│   │   │   │   └── Contents.json
│   │   │   ├── Contents.json
│   │   │   └── magic-keyboard.imageset/
│   │   │       └── Contents.json
│   │   ├── ContentView.swift
│   │   ├── GitHub.swift
│   │   ├── Info.plist
│   │   ├── KeyTap.swift
│   │   ├── KeyboardView.swift
│   │   ├── LeaderboardView.swift
│   │   ├── MenuView.swift
│   │   ├── Preview Content/
│   │   │   └── Preview Assets.xcassets/
│   │   │       └── Contents.json
│   │   ├── SettingsView.swift
│   │   ├── TypingChart.swift
│   │   ├── UserDefaults.swift
│   │   └── keyrace_mac.entitlements
│   ├── keyrace-mac.xcodeproj/
│   │   ├── project.pbxproj
│   │   ├── project.xcworkspace/
│   │   │   ├── contents.xcworkspacedata
│   │   │   └── xcshareddata/
│   │   │       └── IDEWorkspaceChecks.plist
│   │   └── xcshareddata/
│   │       └── xcschemes/
│   │           └── keyrace-mac.xcscheme
│   └── keyrace-mac.xcworkspace/
│       ├── contents.xcworkspacedata
│       └── xcshareddata/
│           └── IDEWorkspaceChecks.plist
└── server.go
Download .txt
SYMBOL INDEX (19 symbols across 2 files)

FILE: keyrace.c
  function update_savefile (line 27) | void update_savefile(int kc)
  function load_savefile (line 35) | int load_savefile(void)
  function upload_count (line 57) | void upload_count(char *name, int count)
  function CGEventRef (line 65) | CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv...
  function strclean (line 98) | void strclean(char *src)
  function run_loop (line 110) | void run_loop(void)
  function main (line 132) | int main(int argc, char **argv)

FILE: server.go
  type PlayerScore (line 26) | type PlayerScore struct
  type Player (line 32) | type Player struct
    method upsertInDB (line 41) | func (p *Player) upsertInDB() error {
    method getLeaderboard (line 167) | func (p Player) getLeaderboard(onlyFollows bool) string {
    method setGitHubDataFromToken (line 261) | func (p *Player) setGitHubDataFromToken() {
    method doGitHubCall (line 287) | func (p Player) doGitHubCall(endpoint string) *http.Response {
  function count (line 106) | func count(w http.ResponseWriter, req *http.Request) {
  function removeFromSlice (line 210) | func removeFromSlice(slice []Player, index int) []Player {
  function getStringParam (line 216) | func getStringParam(req *http.Request, key string) string {
  function humanTime (line 228) | func humanTime(t time.Time) string {
  type GitHubUser (line 254) | type GitHubUser struct
  function main (line 306) | func main() {
Condensed preview — 198 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,185K chars).
[
  {
    "path": ".github/workflows/build_app.yml",
    "chars": 515,
    "preview": "name: build mac app\n\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: macOS-latest\n    steps:\n      - name: Checkou"
  },
  {
    "path": ".github/workflows/make-test.yml",
    "chars": 418,
    "preview": "on: [push, pull_request]\nname: make test\njobs:\n  maketest:\n    name: make test\n    runs-on: ubuntu-latest\n    steps:\n   "
  },
  {
    "path": ".gitignore",
    "chars": 641,
    "preview": "# Xcode .gitignore\n#\n# Source:\n# https://github.com/github/gitignore/blob/master/Global/Xcode.gitignore\n\n## User setting"
  },
  {
    "path": "Makefile",
    "chars": 1197,
    "preview": "SERVER=keyrace.app\nBUILDTAGS=libsqlite3 sqlite_omit_load_extension\n\nkeyrace-server: $(wildcard *.go)\n\tgo mod vendor || t"
  },
  {
    "path": "README.md",
    "chars": 537,
    "preview": "# keyrace\nDaily multiplayer keyboard races for macos\n\n<img width=\"383\" alt=\"image\" src=\"https://user-images.githubuserco"
  },
  {
    "path": "go.mod",
    "chars": 392,
    "preview": "module github.com/nat/keyrace\n\ngo 1.14\n\nrequire (\n\tgithub.com/grpc-ecosystem/go-grpc-middleware v1.2.2 // indirect\n\tgith"
  },
  {
    "path": "go.sum",
    "chars": 12309,
    "preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-2"
  },
  {
    "path": "keyrace.c",
    "chars": 3868,
    "preview": "// NOTE: This client no longer works. Run the native mac client instead!\n//\n// gcc keyrace.c -o keyrace -framework Appli"
  },
  {
    "path": "mac/Podfile",
    "chars": 81,
    "preview": "use_frameworks!\ninhibit_all_warnings!\n\ntarget 'keyrace-mac' do\n\tpod 'Charts'\nend\n"
  },
  {
    "path": "mac/Pods/Charts/LICENSE",
    "chars": 11338,
    "preview": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licens"
  },
  {
    "path": "mac/Pods/Charts/README.md",
    "chars": 12863,
    "preview": "**Version 3.5.0**, synced to [MPAndroidChart #f6a398b](https://github.com/PhilJay/MPAndroidChart/commit/f6a398b)\n\n![alt "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Animation/Animator.swift",
    "chars": 10635,
    "preview": "//\n//  Animator.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Animation/ChartAnimationEasing.swift",
    "chars": 13524,
    "preview": "//\n//  ChartAnimationUtils.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/BarChartView.swift",
    "chars": 6740,
    "preview": "//\n//  BarChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/BarLineChartViewBase.swift",
    "chars": 69393,
    "preview": "//\n//  BarLineChartViewBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/BubbleChartView.swift",
    "chars": 650,
    "preview": "//\n//  BubbleChartView.swift\n//  Charts\n//\n//  Bubble chart implementation:\n//    Copyright 2015 Pierre-Marc Airoldi\n// "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/CandleStickChartView.swift",
    "chars": 829,
    "preview": "//\n//  CandleStickChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/ChartViewBase.swift",
    "chars": 37355,
    "preview": "//\n//  ChartViewBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/CombinedChartView.swift",
    "chars": 7226,
    "preview": "//\n//  CombinedChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/HorizontalBarChartView.swift",
    "chars": 9766,
    "preview": "//\n//  HorizontalBarChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of M"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/LineChartView.swift",
    "chars": 705,
    "preview": "//\n//  LineChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/PieChartView.swift",
    "chars": 18712,
    "preview": "//\n//  PieChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/PieRadarChartViewBase.swift",
    "chars": 27158,
    "preview": "//\n//  PieRadarChartViewBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/RadarChartView.swift",
    "chars": 6951,
    "preview": "//\n//  RadarChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Charts/ScatterChartView.swift",
    "chars": 824,
    "preview": "//\n//  ScatterChartView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/AxisBase.swift",
    "chars": 12198,
    "preview": "//\n//  AxisBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/ChartLimitLine.swift",
    "chars": 1896,
    "preview": "//\n//  ChartLimitLine.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/ComponentBase.swift",
    "chars": 901,
    "preview": "//\n//  ComponentBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/Description.swift",
    "chars": 1315,
    "preview": "//\n//  Description.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/IMarker.swift",
    "chars": 1741,
    "preview": "//\n//  ChartMarker.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/Legend.swift",
    "chars": 14379,
    "preview": "//\n//  Legend.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart fo"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/LegendEntry.swift",
    "chars": 2971,
    "preview": "//\n//  LegendEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/MarkerImage.swift",
    "chars": 2585,
    "preview": "//\n//  ChartMarkerImage.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/MarkerView.swift",
    "chars": 2549,
    "preview": "//\n//  ChartMarkerView.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/XAxis.swift",
    "chars": 2511,
    "preview": "//\n//  XAxis.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart for"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Components/YAxis.swift",
    "chars": 6039,
    "preview": "//\n//  YAxis.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart for"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/ChartBaseDataSet.swift",
    "chars": 12991,
    "preview": "//\n//  BaseDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartData.swift",
    "chars": 3359,
    "preview": "//\n//  BarChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift",
    "chars": 5902,
    "preview": "//\n//  BarChartDataEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift",
    "chars": 4857,
    "preview": "//\n//  BarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift",
    "chars": 492,
    "preview": "//\n//  BarLineScatterCandleBubbleChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift",
    "chars": 1189,
    "preview": "//\n//  BarLineScatterCandleBubbleChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift",
    "chars": 782,
    "preview": "//\n//  BubbleChartData.swift\n//  Charts\n//\n//  Bubble chart implementation:\n//    Copyright 2015 Pierre-Marc Airoldi\n// "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataEntry.swift",
    "chars": 2109,
    "preview": "//\n//  BubbleDataEntry.swift\n//  Charts\n//\n//  Bubble chart implementation: \n//    Copyright 2015 Pierre-Marc Airoldi\n//"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift",
    "chars": 1517,
    "preview": "//\n//  BubbleChartDataSet.swift\n//  Charts\n//\n//  Bubble chart implementation:\n//    Copyright 2015 Pierre-Marc Airoldi\n"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartData.swift",
    "chars": 478,
    "preview": "//\n//  CandleChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataEntry.swift",
    "chars": 2543,
    "preview": "//\n//  CandleChartDataEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift",
    "chars": 3286,
    "preview": "//\n//  CandleChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAnd"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartData.swift",
    "chars": 18034,
    "preview": "//\n//  ChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift",
    "chars": 2605,
    "preview": "//\n//  ChartDataEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartDataEntryBase.swift",
    "chars": 2141,
    "preview": "//\n//  ChartDataEntryBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAnd"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift",
    "chars": 17565,
    "preview": "//\n//  ChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift",
    "chars": 7418,
    "preview": "//\n//  CombinedChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartData.swift",
    "chars": 520,
    "preview": "//\n//  LineChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift",
    "chars": 5082,
    "preview": "//\n//  LineChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift",
    "chars": 2324,
    "preview": "//\n//  LineRadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift",
    "chars": 1877,
    "preview": "//\n//  LineScatterCandleRadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n// "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartData.swift",
    "chars": 2996,
    "preview": "//\n//  PieData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart f"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartDataEntry.swift",
    "chars": 3098,
    "preview": "//\n//  PieChartDataEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift",
    "chars": 4047,
    "preview": "//\n//  PieChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartData.swift",
    "chars": 1271,
    "preview": "//\n//  RadarChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataEntry.swift",
    "chars": 1140,
    "preview": "//\n//  RadarChartDataEntry.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift",
    "chars": 1580,
    "preview": "//\n//  RadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift",
    "chars": 788,
    "preview": "//\n//  ScatterChartData.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift",
    "chars": 2481,
    "preview": "//\n//  ScatterChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IBarChartDataSet.swift",
    "chars": 1423,
    "preview": "//\n//  IBarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift",
    "chars": 670,
    "preview": "//\n//  IBarLineScatterCandleBubbleChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahod"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift",
    "chars": 671,
    "preview": "//\n//  IBubbleChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/ICandleChartDataSet.swift",
    "chars": 1822,
    "preview": "//\n//  ICandleChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IChartDataSet.swift",
    "chars": 11269,
    "preview": "//\n//  IChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/ILineChartDataSet.swift",
    "chars": 2653,
    "preview": "//\n//  ILineChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift",
    "chars": 1400,
    "preview": "//\n//  ILineRadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of M"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift",
    "chars": 1242,
    "preview": "//\n//  ILineScatterCandleRadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IPieChartDataSet.swift",
    "chars": 2145,
    "preview": "//\n//  IPieChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IRadarChartDataSet.swift",
    "chars": 1085,
    "preview": "//\n//  IRadarChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAnd"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Data/Interfaces/IScatterChartDataSet.swift",
    "chars": 1050,
    "preview": "//\n//  IScatterChartDataSet.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Filters/DataApproximator+N.swift",
    "chars": 4648,
    "preview": "//\n//  DataApproximator+N.swift\n//  Charts\n//\n//  Created by M Ivaniushchenko on 9/6/17.\n//  Licensed under Apache Licen"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Filters/DataApproximator.swift",
    "chars": 3289,
    "preview": "//\n//  DataApproximator.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/DefaultAxisValueFormatter.swift",
    "chars": 2380,
    "preview": "//\n//  DefaultAxisValueFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port o"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/DefaultFillFormatter.swift",
    "chars": 1515,
    "preview": "//\n//  DefaultFillFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/DefaultValueFormatter.swift",
    "chars": 2536,
    "preview": "//\n//  DefaultValueFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/IAxisValueFormatter.swift",
    "chars": 897,
    "preview": "//\n//  IAxisValueFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/IFillFormatter.swift",
    "chars": 692,
    "preview": "//\n//  IFillFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/IValueFormatter.swift",
    "chars": 1346,
    "preview": "//\n//  IValueFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Formatters/IndexAxisValueFormatter.swift",
    "chars": 1357,
    "preview": "//\n//  IndexAxisValueFormatter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/BarHighlighter.swift",
    "chars": 3450,
    "preview": "//\n//  BarHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/ChartHighlighter.swift",
    "chars": 6260,
    "preview": "//\n//  ChartHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/CombinedHighlighter.swift",
    "chars": 2187,
    "preview": "//\n//  CombinedHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/Highlight.swift",
    "chars": 6677,
    "preview": "//\n//  Highlight.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/HorizontalBarHighlighter.swift",
    "chars": 2115,
    "preview": "//\n//  HorizontalBarHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/IHighlighter.swift",
    "chars": 537,
    "preview": "//\n//  IHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/PieHighlighter.swift",
    "chars": 714,
    "preview": "//\n//  PieHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/PieRadarHighlighter.swift",
    "chars": 1673,
    "preview": "//\n//  PieRadarHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/RadarHighlighter.swift",
    "chars": 2466,
    "preview": "//\n//  RadarHighlighter.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Highlight/Range.swift",
    "chars": 1039,
    "preview": "//\n//  Range.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart for"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/BarChartDataProvider.swift",
    "chars": 543,
    "preview": "//\n//  BarChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift",
    "chars": 588,
    "preview": "//\n//  BarLineScatterCandleBubbleChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp J"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/BubbleChartDataProvider.swift",
    "chars": 408,
    "preview": "//\n//  BubbleChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/CandleChartDataProvider.swift",
    "chars": 408,
    "preview": "//\n//  CandleChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/ChartDataProvider.swift",
    "chars": 977,
    "preview": "//\n//  ChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/CombinedChartDataProvider.swift",
    "chars": 492,
    "preview": "//\n//  CombinedChartDataProvider.swoft\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port o"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/LineChartDataProvider.swift",
    "chars": 462,
    "preview": "//\n//  LineChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Interfaces/ScatterChartDataProvider.swift",
    "chars": 412,
    "preview": "//\n//  ScatterChartDataProvider.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/AnimatedMoveViewJob.swift",
    "chars": 822,
    "preview": "//\n//  AnimatedMoveViewJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/AnimatedViewPortJob.swift",
    "chars": 3005,
    "preview": "//\n//  AnimatedViewPortJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/AnimatedZoomViewJob.swift",
    "chars": 2959,
    "preview": "//\n//  AnimatedZoomViewJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/MoveViewJob.swift",
    "chars": 734,
    "preview": "//\n//  MoveViewJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/ViewPortJob.swift",
    "chars": 1180,
    "preview": "//\n//  ViewPortJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Jobs/ZoomViewJob.swift",
    "chars": 2090,
    "preview": "//\n//  ZoomViewJob.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/AxisRendererBase.swift",
    "chars": 6939,
    "preview": "//\n//  AxisRendererBase.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/BarChartRenderer.swift",
    "chars": 39137,
    "preview": "//\n//  BarChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift",
    "chars": 4474,
    "preview": "//\n//  BarLineScatterCandleBubbleRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n// "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/BubbleChartRenderer.swift",
    "chars": 14487,
    "preview": "//\n//  BubbleChartRenderer.swift\n//  Charts\n//\n//  Bubble chart implementation:\n//    Copyright 2015 Pierre-Marc Airoldi"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/CandleStickChartRenderer.swift",
    "chars": 16341,
    "preview": "//\n//  CandleStickChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/ChartDataRendererBase.swift",
    "chars": 3829,
    "preview": "//\n//  DataRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCh"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/CombinedChartRenderer.swift",
    "chars": 7141,
    "preview": "//\n//  CombinedChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/HorizontalBarChartRenderer.swift",
    "chars": 25628,
    "preview": "//\n//  HorizontalBarChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/LegendRenderer.swift",
    "chars": 20712,
    "preview": "//\n//  LegendRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/LineChartRenderer.swift",
    "chars": 30352,
    "preview": "//\n//  LineChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/LineRadarRenderer.swift",
    "chars": 1550,
    "preview": "//\n//  LineRadarRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift",
    "chars": 1574,
    "preview": "//\n//  LineScatterCandleRadarRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A p"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/PieChartRenderer.swift",
    "chars": 37652,
    "preview": "//\n//  PieChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndro"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/RadarChartRenderer.swift",
    "chars": 18229,
    "preview": "//\n//  RadarChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAnd"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Renderer.swift",
    "chars": 582,
    "preview": "//\n//  Renderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift",
    "chars": 1112,
    "preview": "//\n//  ChevronDownShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift",
    "chars": 1108,
    "preview": "//\n//  ChevronUpShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of M"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift",
    "chars": 2172,
    "preview": "//\n//  CircleShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift",
    "chars": 1052,
    "preview": "//\n//  CrossShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAnd"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/IShapeRenderer.swift",
    "chars": 882,
    "preview": "//\n//  IShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift",
    "chars": 2139,
    "preview": "//\n//  SquareShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift",
    "chars": 2553,
    "preview": "//\n//  TriangleShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MP"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/Scatter/XShapeRenderer.swift",
    "chars": 1092,
    "preview": "//\n//  XShapeRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/ScatterChartRenderer.swift",
    "chars": 9157,
    "preview": "//\n//  ScatterChartRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPA"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/XAxisRenderer.swift",
    "chars": 15171,
    "preview": "//\n//  XAxisRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift",
    "chars": 12730,
    "preview": "//\n//  XAxisRendererHorizontalBarChart.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/XAxisRendererRadarChart.swift",
    "chars": 2902,
    "preview": "//\n//  XAxisRendererRadarChart.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/YAxisRenderer.swift",
    "chars": 12761,
    "preview": "//\n//  YAxisRenderer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidC"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift",
    "chars": 12406,
    "preview": "//\n//  YAxisRendererHorizontalBarChart.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Renderers/YAxisRendererRadarChart.swift",
    "chars": 8241,
    "preview": "//\n//  YAxisRendererRadarChart.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/ChartColorTemplates.swift",
    "chars": 7888,
    "preview": "//\n//  ChartColorTemplates.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAn"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/ChartUtils.swift",
    "chars": 9708,
    "preview": "//\n//  Utils.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart for"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Fill.swift",
    "chars": 8430,
    "preview": "//\n//  Fill.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidChart for "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform+Accessibility.swift",
    "chars": 5951,
    "preview": "//\n//  Platform+Accessibility.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of M"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform+Color.swift",
    "chars": 995,
    "preview": "//\n//  Platform+Color.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroid"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform+Gestures.swift",
    "chars": 4159,
    "preview": "//\n//  Platform+Gestures.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform+Graphics.swift",
    "chars": 4097,
    "preview": "//\n//  Platform+Graphics.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndr"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform+Touch Handling.swift",
    "chars": 3615,
    "preview": "//\n//  Platform+Touch Handling.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of "
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Platform.swift",
    "chars": 5326,
    "preview": "import Foundation\n\n/** This file provides a thin abstraction layer atop of UIKit (iOS, tvOS) and Cocoa (OS X). The two A"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/Transformer.swift",
    "chars": 5690,
    "preview": "//\n//  Transformer.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroidCha"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/TransformerHorizontalBarChart.swift",
    "chars": 999,
    "preview": "//\n//  TransformerHorizontalBarChart.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A po"
  },
  {
    "path": "mac/Pods/Charts/Source/Charts/Utils/ViewPortHandler.swift",
    "chars": 18381,
    "preview": "//\n//  ViewPortHandler.swift\n//  Charts\n//\n//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda\n//  A port of MPAndroi"
  },
  {
    "path": "mac/Pods/Pods.xcodeproj/project.pbxproj",
    "chars": 109537,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 50;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "mac/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Charts.xcscheme",
    "chars": 2021,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1240\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "mac/Pods/Pods.xcodeproj/xcshareddata/xcschemes/Pods-keyrace-mac.xcscheme",
    "chars": 2041,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1240\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts-Info.plist",
    "chars": 828,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts-dummy.m",
    "chars": 116,
    "preview": "#import <Foundation/Foundation.h>\n@interface PodsDummy_Charts : NSObject\n@end\n@implementation PodsDummy_Charts\n@end\n"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts-prefix.pch",
    "chars": 195,
    "preview": "#ifdef __OBJC__\n#import <Cocoa/Cocoa.h>\n#else\n#ifndef FOUNDATION_EXPORT\n#if defined(__cplusplus)\n#define FOUNDATION_EXPO"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts-umbrella.h",
    "chars": 304,
    "preview": "#ifdef __OBJC__\n#import <Cocoa/Cocoa.h>\n#else\n#ifndef FOUNDATION_EXPORT\n#if defined(__cplusplus)\n#define FOUNDATION_EXPO"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts.debug.xcconfig",
    "chars": 678,
    "preview": "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO\nCODE_SIGN_IDENTITY =\nCONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_B"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts.modulemap",
    "chars": 102,
    "preview": "framework module Charts {\n  umbrella header \"Charts-umbrella.h\"\n\n  export *\n  module * { export * }\n}\n"
  },
  {
    "path": "mac/Pods/Target Support Files/Charts/Charts.release.xcconfig",
    "chars": 678,
    "preview": "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO\nCODE_SIGN_IDENTITY =\nCONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_B"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-Info.plist",
    "chars": 828,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-acknowledgements.markdown",
    "chars": 11484,
    "preview": "# Acknowledgements\nThis application makes use of the following third party libraries:\n\n## Charts\n\nApache License\n       "
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-acknowledgements.plist",
    "chars": 12385,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-dummy.m",
    "chars": 136,
    "preview": "#import <Foundation/Foundation.h>\n@interface PodsDummy_Pods_keyrace_mac : NSObject\n@end\n@implementation PodsDummy_Pods_k"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks-Debug-input-files.xcfilelist",
    "chars": 127,
    "preview": "${PODS_ROOT}/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks.sh\n${BUILT_PRODUCTS_DIR}/Charts/Charts.fr"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks-Debug-output-files.xcfilelist",
    "chars": 62,
    "preview": "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks-Release-input-files.xcfilelist",
    "chars": 127,
    "preview": "${PODS_ROOT}/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks.sh\n${BUILT_PRODUCTS_DIR}/Charts/Charts.fr"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks-Release-output-files.xcfilelist",
    "chars": 62,
    "preview": "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Charts.framework"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-frameworks.sh",
    "chars": 8442,
    "preview": "#!/bin/sh\nset -e\nset -u\nset -o pipefail\n\nfunction on_error {\n  echo \"$(realpath -mq \"${0}\"):$1: error: Unexpected failur"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac-umbrella.h",
    "chars": 324,
    "preview": "#ifdef __OBJC__\n#import <Cocoa/Cocoa.h>\n#else\n#ifndef FOUNDATION_EXPORT\n#if defined(__cplusplus)\n#define FOUNDATION_EXPO"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac.debug.xcconfig",
    "chars": 1005,
    "preview": "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES\nCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO\nFRAMEWORK_SEARCH_PATHS = "
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac.modulemap",
    "chars": 122,
    "preview": "framework module Pods_keyrace_mac {\n  umbrella header \"Pods-keyrace-mac-umbrella.h\"\n\n  export *\n  module * { export * }\n"
  },
  {
    "path": "mac/Pods/Target Support Files/Pods-keyrace-mac/Pods-keyrace-mac.release.xcconfig",
    "chars": 1005,
    "preview": "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES\nCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO\nFRAMEWORK_SEARCH_PATHS = "
  },
  {
    "path": "mac/keyrace-mac/AppDelegate.swift",
    "chars": 2324,
    "preview": "//\n//  keyrace-mac\n//\n//  Created by Nat Friedman on 1/2/21.\n//\n\nimport Cocoa\nimport Foundation\nimport SwiftUI\n\n@availab"
  },
  {
    "path": "mac/keyrace-mac/Assets.xcassets/AccentColor.colorset/Contents.json",
    "chars": 123,
    "preview": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }"
  },
  {
    "path": "mac/keyrace-mac/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 904,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"mac\",\n      \"scale\" : \"1x\",\n      \"size\" : \"16x16\"\n    },\n    {\n      \"idiom\" : "
  },
  {
    "path": "mac/keyrace-mac/Assets.xcassets/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "mac/keyrace-mac/Assets.xcassets/magic-keyboard.imageset/Contents.json",
    "chars": 400,
    "preview": "{\n  \"images\" : [\n    {\n      \"filename\" : \"magic-keyboard.png\",\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },"
  },
  {
    "path": "mac/keyrace-mac/ContentView.swift",
    "chars": 1554,
    "preview": "//\n//  ContentView.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/21/21.\n//\n\nimport Foundation\nimport Swif"
  },
  {
    "path": "mac/keyrace-mac/GitHub.swift",
    "chars": 7741,
    "preview": "//\n//  github_auth.swift\n//  keyrace-mac\n//\n//  Created by Nat Friedman on 1/2/21.\n//\nimport Cocoa\nimport Combine\nimport"
  },
  {
    "path": "mac/keyrace-mac/Info.plist",
    "chars": 841,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/keyrace-mac/KeyTap.swift",
    "chars": 13819,
    "preview": "// Created by Nat Friedman on 1/2/21.\n\nimport Accessibility\nimport Cocoa\nimport Combine\nimport Foundation\nimport SwiftUI"
  },
  {
    "path": "mac/keyrace-mac/KeyboardView.swift",
    "chars": 6679,
    "preview": "//\n//  KeyboardView.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/21/21.\n//\n\nimport Foundation\nimport Swi"
  },
  {
    "path": "mac/keyrace-mac/LeaderboardView.swift",
    "chars": 3880,
    "preview": "//\n//  LeaderboardView.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/20/21.\n//\n\nimport Foundation\nimport "
  },
  {
    "path": "mac/keyrace-mac/MenuView.swift",
    "chars": 123,
    "preview": "//\n//  MenuView.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/21/21.\n//\n\nimport Foundation\nimport SwiftUI"
  },
  {
    "path": "mac/keyrace-mac/Preview Content/Preview Assets.xcassets/Contents.json",
    "chars": 63,
    "preview": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "mac/keyrace-mac/SettingsView.swift",
    "chars": 2674,
    "preview": "//\n//  SettingsView.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/16/21.\n//\n\nimport Foundation\nimport Swi"
  },
  {
    "path": "mac/keyrace-mac/TypingChart.swift",
    "chars": 3930,
    "preview": "//\n//  MenubarItem.swift\n//  keyrace-mac\n//\n//  Created by Nat Friedman on 1/3/21.\n//\n\nimport Charts\nimport Cocoa\nimport"
  },
  {
    "path": "mac/keyrace-mac/UserDefaults.swift",
    "chars": 1444,
    "preview": "//\n//  UserDefaults.swift\n//  keyrace-mac\n//\n//  Created by Jessie Frazelle on 2/21/21.\n//\n\nimport Foundation\n\n// Store "
  },
  {
    "path": "mac/keyrace-mac/keyrace_mac.entitlements",
    "chars": 181,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/keyrace-mac.xcodeproj/project.pbxproj",
    "chars": 19056,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "mac/keyrace-mac.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "chars": 135,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef"
  },
  {
    "path": "mac/keyrace-mac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "mac/keyrace-mac.xcodeproj/xcshareddata/xcschemes/keyrace-mac.xcscheme",
    "chars": 2876,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1240\"\n   version = \"1.3\">\n   <BuildAction\n      "
  },
  {
    "path": "mac/keyrace-mac.xcworkspace/contents.xcworkspacedata",
    "chars": 229,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"group:keyrace-mac.xc"
  },
  {
    "path": "mac/keyrace-mac.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "chars": 238,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "server.go",
    "chars": 11171,
    "preview": "package main\n\nimport (\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"strconv"
  }
]

About this extraction

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