aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2025-07-24 14:40:22 +0300
committerArda Serdar Pektezol <1669855+pektezol@users.noreply.github.com>2025-07-24 14:40:22 +0300
commitb0d199936b546c75d4b19d99591237f0bf97fe55 (patch)
treee9391880e7db2bd1ea8ff25d91aeea8dd98f186e
parentfix/frontend: fixed sidebar title size, removed unnecessary imports (diff)
parentfeat/backend: add newrelic integration (#274) (diff)
downloadlphub-b0d199936b546c75d4b19d99591237f0bf97fe55.tar.gz
lphub-b0d199936b546c75d4b19d99591237f0bf97fe55.tar.bz2
lphub-b0d199936b546c75d4b19d99591237f0bf97fe55.zip
Merge branch 'main' into css-overhaulcss-overhaul
-rw-r--r--CONTRIBUTORS.md30
-rw-r--r--README.md28
-rw-r--r--backend/.env.example27
-rw-r--r--backend/database/init.sql1
-rw-r--r--backend/database/insert/history.sql1
-rw-r--r--backend/database/insert/maps.sql2
-rw-r--r--backend/go.mod25
-rw-r--r--backend/go.sum124
-rw-r--r--backend/handlers/home.go12
-rw-r--r--backend/handlers/map.go10
-rw-r--r--backend/handlers/record.go222
-rw-r--r--backend/handlers/user.go19
-rw-r--r--backend/main.go11
-rw-r--r--backend/models/models.go1
-rw-r--r--backend/parser/parser.go10
-rw-r--r--frontend/package-lock.json38
-rw-r--r--frontend/package.json2
-rw-r--r--frontend/public/index.html41
-rw-r--r--frontend/public/response.json4984
-rw-r--r--frontend/src/App.tsx11
-rw-r--r--frontend/src/api/Api.ts4
-rw-r--r--frontend/src/api/Maps.ts14
-rw-r--r--frontend/src/components/Leaderboards.tsx21
-rw-r--r--frontend/src/components/Summary.tsx36
-rw-r--r--frontend/src/components/UploadRunDialog.tsx106
-rw-r--r--frontend/src/pages/About.tsx4
-rw-r--r--frontend/src/pages/Games.tsx4
-rw-r--r--frontend/src/pages/Homepage.tsx6
-rw-r--r--frontend/src/pages/Maplist.tsx50
-rw-r--r--frontend/src/pages/Maps.tsx41
-rw-r--r--frontend/src/pages/Profile.tsx9
-rw-r--r--frontend/src/pages/Rankings.tsx30
-rw-r--r--frontend/src/pages/Rules.tsx4
-rw-r--r--frontend/src/pages/User.tsx9
-rw-r--r--frontend/src/types/Content.ts1
-rw-r--r--frontend/src/types/Map.ts1
-rw-r--r--frontend/src/types/MapNames.ts127
-rw-r--r--rankings/fetch.go50
-rw-r--r--rankings/input/records.json4
-rw-r--r--rankings/main.go5
40 files changed, 662 insertions, 5463 deletions
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
new file mode 100644
index 0000000..817aead
--- /dev/null
+++ b/CONTRIBUTORS.md
@@ -0,0 +1,30 @@
1# LPHUB Contributors
2
3## Project Team
4
5* [@pektezol](https://github.com/pektezol) - Project Lead
6* [@Krzyhau](https://github.com/Krzyhau) - Visual Design
7* [@Nidboj132](https://github.com/Nidboj132) - Subject Expert & Frontend
8* [@Oryn](https://github.com/Oryn-Goia) - Subject Expert
9* [@Wolfboy248](https://github.com/Wolfboy248) - Frontend
10* [@FifthWit](https://github.com/FifthWit) - Frontend
11* [@NeKz](https://github.com/NeKzor) - Backend & Operations
12
13## Content Contributors
14
15* Black_Semka
16* Feliser
17* Jaio
18* Jess3n
19* Robotwars1
20* SuperAiderton
21* Thearus
22
23## Special Thanks
24
25* [@NeKz](https://github.com/NeKzor) - For being the inspiration of this project and the developer of the former least portals site found [here](https://github.com/NeKzor/lp). Also for creating the [@nekz/sdp](https://github.com/NeKzor/sdp) package for demo parsing in client-side for quick information.
26* [@UncraftedName](https://github.com/UncraftedName) - For being a guide to parsing demo files and helping with how to retrieve total portal count and elapsed time from the CM counter with their parser found [here](https://github.com/UncraftedName/UntitledParser).
27
28## Last Update
29
302024-11-25
diff --git a/README.md b/README.md
index ad5bf3d..1831813 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
1# Least Portals Hub (LPHUB) 1# LPHUB - Least Portals Hub
2 2
3## About LPHUB 3## About LPHUB
4 4
@@ -10,27 +10,9 @@ In addition, we host a leaderboard section for each map where users can compare
10 10
11There's also discussion tabs for each map to act like forum pages in order to talk about possible new routes, alternatives, and overall comments. 11There's also discussion tabs for each map to act like forum pages in order to talk about possible new routes, alternatives, and overall comments.
12 12
13## Project Team 13## Contributors
14 14
15* [@pektezol](https://github.com/pektezol) - Project Lead 15Full list of contributors can be found in the [CONTRIBUTORS](https://github.com/pektezol/lphub/blob/main/CONTRIBUTORS.md) file.
16* [@Krzyhau](https://github.com/Krzyhau) - Visual Design
17* [@Nidboj132](https://github.com/Nidboj132) - Subject Expert & Frontend
18* [@Oryn](https://github.com/Oryn-Goia) - Subject Expert
19* [@Wolfboy248](https://github.com/Wolfboy248) - Frontend
20
21## Content Contributors
22
23* Black_Semka
24* Feliser
25* Jaio
26* Jess3n
27* Robotwars1
28* Thearus
29
30## Special Thanks
31
32* [@NeKz](https://github.com/NeKzor) - For being the inspiration of this project and the developer of the former least portals site found [here](https://github.com/NeKzor/lp). Also for creating the [@nekz/sdp](https://github.com/NeKzor/sdp) package for demo parsing in client-side for quick information.
33* [@UncraftedName](https://github.com/UncraftedName) - For being a guide to parsing demo files and helping with how to retrieve total portal count and elapsed time from the CM counter with their parser found [here](https://github.com/UncraftedName/UntitledParser).
34 16
35## Documentation 17## Documentation
36 18
@@ -53,7 +35,7 @@ If you want to support the creator, you can do it via using GitHub sponsorships
53* We store a JWT (JSON Web Token) on your device as a cookie to facilitate authentication to LPHUB. 35* We store a JWT (JSON Web Token) on your device as a cookie to facilitate authentication to LPHUB.
54* We collect and store your publicly available id, username, avatar link, and country code from Steam during your first login to LPHUB. The exact date and time of your LPHUB account creation is also stored. 36* We collect and store your publicly available id, username, avatar link, and country code from Steam during your first login to LPHUB. The exact date and time of your LPHUB account creation is also stored.
55* In a case of profile update, newly changed values replaces the old data, and the update time is also stored. 37* In a case of profile update, newly changed values replaces the old data, and the update time is also stored.
56* All of the demo proof submitted by users are stored in a publicly accessible Google Drive folder. By submitting demo as a proof, you agree that your demo proof becomes available to the public. 38* All of the demo proof submitted by users are stored in a publicly accessible Backblaze B2 bucket. By submitting demo as a proof, you agree that your demo proof becomes available to the public.
57* Any information, ideas, or solutions shared on LPHUB are intended to be openly accessible and available for collaborative purposes. Users should understand that the content they contribute might be viewed and used by others for the purpose of generating insights and solutions. 39* Any information, ideas, or solutions shared on LPHUB are intended to be openly accessible and available for collaborative purposes. Users should understand that the content they contribute might be viewed and used by others for the purpose of generating insights and solutions.
58* At any time, Privacy Policy may get updated to reflect changes in LPHUB. The effective date at the bottom of the README indicates when the most recent changes were made. 40* At any time, Privacy Policy may get updated to reflect changes in LPHUB. The effective date at the bottom of the README indicates when the most recent changes were made.
59 41
@@ -73,4 +55,4 @@ By using LPHUB, you acknowledge that you have read and understood this disclaime
73 55
74## Last Update 56## Last Update
75 57
762024-10-31 \ No newline at end of file 582024-11-25 \ No newline at end of file
diff --git a/backend/.env.example b/backend/.env.example
index 774f2a2..0318aa1 100644
--- a/backend/.env.example
+++ b/backend/.env.example
@@ -1,12 +1,15 @@
1PORT= 1PORT=4000
2SECRET_KEY= 2SECRET_KEY=123456789ABCDEF
3API_KEY= 3API_KEY=123456789ABCDEF
4ENV= 4ENV=DEV
5DB_HOST= 5DB_HOST=localhost
6DB_PORT= 6DB_PORT=5432
7DB_USER= 7DB_USER=postgres
8DB_PASS= 8DB_PASS=postgres
9DB_NAME= 9DB_NAME=postgres
10GOOGLE_CLIENT_EMAIL= 10B2_BUCKET_NAME=lphub
11GOOGLE_PRIVATE_KEY_BASE64= 11B2_KEY_ID=123456789ABCDEF
12GOOGLE_FOLDER_ID= \ No newline at end of file 12B2_API_KEY=123456789ABCDEF
13B2_DOWNLOAD_URL=https://lphub.s3.eu-central-001.backblazeb2.com/
14LOCAL_DEMOS_PATH=/path/to/demos/
15NEWRELIC_LICENSE_KEY=abcdef123456789
diff --git a/backend/database/init.sql b/backend/database/init.sql
index e238eae..d49e519 100644
--- a/backend/database/init.sql
+++ b/backend/database/init.sql
@@ -137,7 +137,6 @@ CREATE TABLE map_discussions_upvotes (
137 137
138CREATE TABLE demos ( 138CREATE TABLE demos (
139 id UUID, 139 id UUID,
140 location_id TEXT NOT NULL,
141 PRIMARY KEY (id) 140 PRIMARY KEY (id)
142); 141);
143 142
diff --git a/backend/database/insert/history.sql b/backend/database/insert/history.sql
index 34fddcb..6b4922a 100644
--- a/backend/database/insert/history.sql
+++ b/backend/database/insert/history.sql
@@ -547,6 +547,7 @@ INSERT INTO map_history(map_id,category_id,user_name,score_count,record_date) VA
547(57,1,'Krank',5,'2012-07-29'), 547(57,1,'Krank',5,'2012-07-29'),
548(57,1,'Krzyhau',0,'2017-10-29'), 548(57,1,'Krzyhau',0,'2017-10-29'),
549(58,1,'Stimich',2,'2011-10-11'), 549(58,1,'Stimich',2,'2011-10-11'),
550(58,1,'Isenstige',0,'2025-01-24'),
550(59,1,'Isimmo',7,'2011-11-04'), 551(59,1,'Isimmo',7,'2011-11-04'),
551(59,1,'sicklebrick',6,'2013-03-20'), 552(59,1,'sicklebrick',6,'2013-03-20'),
552(60,1,'CalmlyFrenetic',7,'2011-10-19'), 553(60,1,'CalmlyFrenetic',7,'2011-10-19'),
diff --git a/backend/database/insert/maps.sql b/backend/database/insert/maps.sql
index f0235fa..e896ba9 100644
--- a/backend/database/insert/maps.sql
+++ b/backend/database/insert/maps.sql
@@ -96,7 +96,7 @@ INSERT INTO maps(game_id, chapter_id, name, is_disabled, image) VALUES
96(2,13,'Catapult Block',false,''), 96(2,13,'Catapult Block',false,''),
97(2,13,'Bridge Fling',false,''), 97(2,13,'Bridge Fling',false,''),
98(2,13,'Turret Walls',false,''), 98(2,13,'Turret Walls',false,''),
99(2,13,'Turret Assasin',false,''), 99(2,13,'Turret Assassin',false,''),
100(2,13,'Bridge Testing',false,''), 100(2,13,'Bridge Testing',false,''),
101-- 4 101-- 4
102(2,14,'Cooperative Funnels',false,''), 102(2,14,'Cooperative Funnels',false,''),
diff --git a/backend/go.mod b/backend/go.mod
index 17308f3..f9fe0db 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -8,6 +8,7 @@ require (
8) 8)
9 9
10require ( 10require (
11 github.com/Backblaze/blazer v0.7.1
11 github.com/golang-jwt/jwt/v4 v4.5.0 12 github.com/golang-jwt/jwt/v4 v4.5.0
12 github.com/google/uuid v1.6.0 13 github.com/google/uuid v1.6.0
13 github.com/pektezol/steam_go v1.1.2 14 github.com/pektezol/steam_go v1.1.2
@@ -18,40 +19,26 @@ require (
18) 19)
19 20
20require ( 21require (
21 cloud.google.com/go/auth v0.9.3 // indirect
22 cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
23 cloud.google.com/go/compute/metadata v0.5.0 // indirect
24 github.com/KyleBanks/depth v1.2.1 // indirect 22 github.com/KyleBanks/depth v1.2.1 // indirect
25 github.com/bytedance/sonic v1.12.2 // indirect 23 github.com/bytedance/sonic v1.12.2 // indirect
26 github.com/bytedance/sonic/loader v0.2.0 // indirect 24 github.com/bytedance/sonic/loader v0.2.0 // indirect
27 github.com/cloudwego/base64x v0.1.4 // indirect 25 github.com/cloudwego/base64x v0.1.4 // indirect
28 github.com/cloudwego/iasm v0.2.0 // indirect 26 github.com/cloudwego/iasm v0.2.0 // indirect
29 github.com/felixge/httpsnoop v1.0.4 // indirect
30 github.com/gabriel-vasile/mimetype v1.4.5 // indirect 27 github.com/gabriel-vasile/mimetype v1.4.5 // indirect
31 github.com/go-logr/logr v1.4.2 // indirect
32 github.com/go-logr/stdr v1.2.2 // indirect
33 github.com/go-openapi/jsonpointer v0.21.0 // indirect 28 github.com/go-openapi/jsonpointer v0.21.0 // indirect
34 github.com/go-openapi/jsonreference v0.21.0 // indirect 29 github.com/go-openapi/jsonreference v0.21.0 // indirect
35 github.com/go-openapi/spec v0.21.0 // indirect 30 github.com/go-openapi/spec v0.21.0 // indirect
36 github.com/go-openapi/swag v0.23.0 // indirect 31 github.com/go-openapi/swag v0.23.0 // indirect
37 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
38 github.com/google/s2a-go v0.1.8 // indirect
39 github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
40 github.com/googleapis/gax-go/v2 v2.13.0 // indirect
41 github.com/josharian/intern v1.0.0 // indirect 32 github.com/josharian/intern v1.0.0 // indirect
42 github.com/klauspost/cpuid/v2 v2.2.8 // indirect 33 github.com/klauspost/cpuid/v2 v2.2.8 // indirect
43 github.com/mailru/easyjson v0.7.7 // indirect 34 github.com/mailru/easyjson v0.7.7 // indirect
35 github.com/newrelic/go-agent/v3 v3.40.1 // indirect
36 github.com/newrelic/go-agent/v3/integrations/nrgin v1.4.1 // indirect
44 github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 37 github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
45 go.opencensus.io v0.24.0 // indirect
46 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
47 go.opentelemetry.io/otel v1.29.0 // indirect
48 go.opentelemetry.io/otel/metric v1.29.0 // indirect
49 go.opentelemetry.io/otel/trace v1.29.0 // indirect
50 golang.org/x/arch v0.10.0 // indirect 38 golang.org/x/arch v0.10.0 // indirect
51 golang.org/x/tools v0.25.0 // indirect 39 golang.org/x/tools v0.25.0 // indirect
52 google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect 40 google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
53 google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect 41 google.golang.org/grpc v1.65.0 // indirect
54 google.golang.org/grpc v1.66.0 // indirect
55 gopkg.in/yaml.v3 v3.0.1 // indirect 42 gopkg.in/yaml.v3 v3.0.1 // indirect
56) 43)
57 44
@@ -72,9 +59,7 @@ require (
72 github.com/ugorji/go/codec v1.2.12 // indirect 59 github.com/ugorji/go/codec v1.2.12 // indirect
73 golang.org/x/crypto v0.27.0 // indirect 60 golang.org/x/crypto v0.27.0 // indirect
74 golang.org/x/net v0.29.0 // indirect 61 golang.org/x/net v0.29.0 // indirect
75 golang.org/x/oauth2 v0.23.0
76 golang.org/x/sys v0.25.0 // indirect 62 golang.org/x/sys v0.25.0 // indirect
77 golang.org/x/text v0.18.0 // indirect 63 golang.org/x/text v0.18.0 // indirect
78 google.golang.org/api v0.196.0
79 google.golang.org/protobuf v1.34.2 // indirect 64 google.golang.org/protobuf v1.34.2 // indirect
80) 65)
diff --git a/backend/go.sum b/backend/go.sum
index 647f6f9..f655023 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -1,11 +1,5 @@
1cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 1github.com/Backblaze/blazer v0.7.1 h1:J43PbFj6hXLg1jvCNr+rQoAsxzKK0IP7ftl1ReCwpcQ=
2cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= 2github.com/Backblaze/blazer v0.7.1/go.mod h1:MhntL1nMpIuoqrPP6TnZu/xTydMgOAe/Xm6KongbjKs=
3cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
4cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
5cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
6cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
7cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
8github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
9github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= 3github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
10github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= 4github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
11github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= 5github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg=
@@ -13,22 +7,13 @@ github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKz
13github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= 7github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
14github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= 8github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
15github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= 9github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
16github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
17github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
18github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= 10github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
19github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 11github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
20github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= 12github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
21github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= 13github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
22github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
23github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 15github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
25github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
26github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
27github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
28github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
29github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
30github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
31github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
32github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= 17github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
33github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= 18github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
34github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= 19github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
@@ -37,11 +22,6 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
37github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 22github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
38github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= 23github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
39github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= 24github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
40github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
41github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
42github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
43github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
44github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
45github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= 25github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
46github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= 26github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
47github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= 27github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
@@ -62,38 +42,11 @@ github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
62github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 42github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
63github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= 43github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
64github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 44github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
65github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
66github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
67github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
68github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
69github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
70github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
71github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
72github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
73github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
74github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
75github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
76github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
77github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
78github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
79github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
80github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
81github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
82github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
83github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
84github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
85github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 45github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
86github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 46github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
87github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 47github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
88github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM=
89github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA=
90github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
91github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 48github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
92github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 49github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
93github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
94github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
95github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
96github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
97github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 50github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
98github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 51github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
99github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 52github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -121,6 +74,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
121github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 74github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
122github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 75github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
123github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 76github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
77github.com/newrelic/go-agent/v3 v3.40.1 h1:8nb4R252Fpuc3oySvlHpDwqySqaPWL5nf7ZVEhqtUeA=
78github.com/newrelic/go-agent/v3 v3.40.1/go.mod h1:X0TLXDo+ttefTIue1V96Y5seb8H6wqf6uUq4UpPsYj8=
79github.com/newrelic/go-agent/v3/integrations/nrgin v1.4.1 h1:a1waTQToxDTKd31LpwpaFHKWPj8Dav/BrzZayBiiAq8=
80github.com/newrelic/go-agent/v3/integrations/nrgin v1.4.1/go.mod h1:mEbfsZIxBYIPT7FzboYvE+ed2ft4SCFXoCvleI2v5JQ=
124github.com/pektezol/bitreader v1.4.3 h1:+WjsD6qOAaI6Q1jOOlEJcnaEso8vPMKRZnnaDnZhTSg= 81github.com/pektezol/bitreader v1.4.3 h1:+WjsD6qOAaI6Q1jOOlEJcnaEso8vPMKRZnnaDnZhTSg=
125github.com/pektezol/bitreader v1.4.3/go.mod h1:xBQEsQpOf8B5yPrnOTkirZGyVUV6Bqp0ups2RIlTskk= 82github.com/pektezol/bitreader v1.4.3/go.mod h1:xBQEsQpOf8B5yPrnOTkirZGyVUV6Bqp0ups2RIlTskk=
126github.com/pektezol/steam_go v1.1.2 h1:fta6SW+La8NfmCtR/Kn73bAmTBvCgUkkLCplsJGzx7g= 83github.com/pektezol/steam_go v1.1.2 h1:fta6SW+La8NfmCtR/Kn73bAmTBvCgUkkLCplsJGzx7g=
@@ -129,7 +86,6 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
129github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= 86github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
130github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 87github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
131github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 88github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
132github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
133github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= 89github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
134github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= 90github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
135github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 91github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -153,55 +109,26 @@ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2
153github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= 109github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
154github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 110github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
155github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 111github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
156go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
157go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
158go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
159go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
160go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
161go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
162go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
163go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
164go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
165go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
166golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= 112golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8=
167golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 113golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
168golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 114golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
169golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
170golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 115golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
171golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= 116golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
172golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= 117golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
173golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
174golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
175golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
176golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
177golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 118golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
178golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= 119golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
179golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 120golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
180golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
181golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
182golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
183golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
184golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
185golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 121golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
186golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
187golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 122golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
188golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 123golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
189golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 124golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
190golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= 125golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
191golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 126golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
192golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
193golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
194golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
195golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
196golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
197golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 127golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
198golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 128golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
199golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 129golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
200golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 130golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
201golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
202golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 131golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
203golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
204golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
205golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 132golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
206golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 133golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
207golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 134golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -222,43 +149,16 @@ golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
222golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= 149golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
223golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 150golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
224golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 151golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
225golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
226golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
227golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
228golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
229golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 152golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
230golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 153golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
231golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= 154golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
232golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= 155golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
233golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 156golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
234golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 157google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0=
235google.golang.org/api v0.196.0 h1:k/RafYqebaIJBO3+SMnfEGtFVlvp5vSgqTUF54UN/zg= 158google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
236google.golang.org/api v0.196.0/go.mod h1:g9IL21uGkYgvQ5BZg6BAtoGJQIm8r6EgaAbpNey5wBE= 159google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
237google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 160google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
238google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 161google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
239google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
240google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
241google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
242google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
243google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
244google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
245google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
246google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
247google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
248google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
249google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
250google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
251google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
252google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
253google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
254google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
255google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
256google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
257google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
258google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
259google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
260google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
261google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
262google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 162google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
263google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 163google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
264gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 164gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -267,6 +167,4 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
267gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 167gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
268gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 168gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
269gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 169gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
270honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
271honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
272nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 170nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
diff --git a/backend/handlers/home.go b/backend/handlers/home.go
index 714610a..095b666 100644
--- a/backend/handlers/home.go
+++ b/backend/handlers/home.go
@@ -6,6 +6,7 @@ import (
6 "log" 6 "log"
7 "net/http" 7 "net/http"
8 "os" 8 "os"
9 "sort"
9 "strings" 10 "strings"
10 11
11 "lphub/database" 12 "lphub/database"
@@ -106,6 +107,15 @@ func RankingsLPHUB(c *gin.Context) {
106 } 107 }
107 } 108 }
108 } 109 }
110 // Sort the overall rankings
111 sort.Slice(response.Overall, func(i, j int) bool {
112 a := response.Overall[i]
113 b := response.Overall[j]
114 if a.TotalScore == b.TotalScore {
115 return a.User.SteamID < b.User.SteamID
116 }
117 return a.TotalScore < b.TotalScore
118 })
109 119
110 placement := 1 120 placement := 1
111 ties := 0 121 ties := 0
@@ -317,7 +327,7 @@ func SearchWithQuery(c *gin.Context) {
317 {ID: 80, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Catapult Block"}, 327 {ID: 80, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Catapult Block"},
318 {ID: 81, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Bridge Fling"}, 328 {ID: 81, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Bridge Fling"},
319 {ID: 82, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Turret Walls"}, 329 {ID: 82, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Turret Walls"},
320 {ID: 83, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Turret Assasin"}, 330 {ID: 83, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Turret Assassin"},
321 {ID: 84, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Bridge Testing"}, 331 {ID: 84, Game: "Portal 2 - Cooperative", Chapter: "Course 3 - Hard-Light Surfaces", Map: "Bridge Testing"},
322 {ID: 85, Game: "Portal 2 - Cooperative", Chapter: "Course 4 - Excursion Funnels", Map: "Cooperative Funnels"}, 332 {ID: 85, Game: "Portal 2 - Cooperative", Chapter: "Course 4 - Excursion Funnels", Map: "Cooperative Funnels"},
323 {ID: 86, Game: "Portal 2 - Cooperative", Chapter: "Course 4 - Excursion Funnels", Map: "Funnel Drill"}, 333 {ID: 86, Game: "Portal 2 - Cooperative", Chapter: "Course 4 - Excursion Funnels", Map: "Funnel Drill"},
diff --git a/backend/handlers/map.go b/backend/handlers/map.go
index b2a0b91..9cb0bcc 100644
--- a/backend/handlers/map.go
+++ b/backend/handlers/map.go
@@ -77,12 +77,12 @@ func FetchMapSummary(c *gin.Context) {
77 } 77 }
78 // Get map data 78 // Get map data
79 response.Map.ID = intID 79 response.Map.ID = intID
80 sql := `SELECT m.id, g.name, c.name, m.name, m.image, g.is_coop, m.is_disabled 80 sql := `SELECT m.id, g.name, c.name, m.name, m.image, g.is_coop, m.is_disabled, m.difficulty
81 FROM maps m 81 FROM maps m
82 INNER JOIN games g ON m.game_id = g.id 82 INNER JOIN games g ON m.game_id = g.id
83 INNER JOIN chapters c ON m.chapter_id = c.id 83 INNER JOIN chapters c ON m.chapter_id = c.id
84 WHERE m.id = $1` 84 WHERE m.id = $1`
85 err = database.DB.QueryRow(sql, id).Scan(&response.Map.ID, &response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &response.Map.Image, &response.Map.IsCoop, &response.Map.IsDisabled) 85 err = database.DB.QueryRow(sql, id).Scan(&response.Map.ID, &response.Map.GameName, &response.Map.ChapterName, &response.Map.MapName, &response.Map.Image, &response.Map.IsCoop, &response.Map.IsDisabled, &response.Map.Difficulty)
86 if err != nil { 86 if err != nil {
87 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 87 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
88 return 88 return
@@ -492,6 +492,7 @@ func FetchMaps(c *gin.Context) {
492 m.id, 492 m.id,
493 m.name, 493 m.name,
494 m.is_disabled, 494 m.is_disabled,
495 m.difficulty,
495 m.image, 496 m.image,
496 cat.id, 497 cat.id,
497 cat.name, 498 cat.name,
@@ -529,7 +530,7 @@ func FetchMaps(c *gin.Context) {
529 for rows.Next() { 530 for rows.Next() {
530 var mapShort models.MapSelect 531 var mapShort models.MapSelect
531 var categoryPortal models.CategoryPortal 532 var categoryPortal models.CategoryPortal
532 if err := rows.Scan(&mapShort.ID, &mapShort.Name, &mapShort.IsDisabled, &mapShort.Image, &categoryPortal.Category.ID, &categoryPortal.Category.Name, &categoryPortal.PortalCount); err != nil { 533 if err := rows.Scan(&mapShort.ID, &mapShort.Name, &mapShort.IsDisabled, &mapShort.Difficulty, &mapShort.Image, &categoryPortal.Category.ID, &categoryPortal.Category.Name, &categoryPortal.PortalCount); err != nil {
533 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 534 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
534 return 535 return
535 } 536 }
@@ -571,6 +572,7 @@ func FetchChapterMaps(c *gin.Context) {
571 m.name AS map_name, 572 m.name AS map_name,
572 c.name AS chapter_name, 573 c.name AS chapter_name,
573 m.is_disabled, 574 m.is_disabled,
575 m.difficulty,
574 m.image, 576 m.image,
575 cat.id, 577 cat.id,
576 cat.name, 578 cat.name,
@@ -610,7 +612,7 @@ func FetchChapterMaps(c *gin.Context) {
610 for rows.Next() { 612 for rows.Next() {
611 var mapShort models.MapSelect 613 var mapShort models.MapSelect
612 var categoryPortal models.CategoryPortal 614 var categoryPortal models.CategoryPortal
613 if err := rows.Scan(&mapShort.ID, &mapShort.Name, &chapterName, &mapShort.IsDisabled, &mapShort.Image, &categoryPortal.Category.ID, &categoryPortal.Category.Name, &categoryPortal.PortalCount); err != nil { 615 if err := rows.Scan(&mapShort.ID, &mapShort.Name, &chapterName, &mapShort.IsDisabled, &mapShort.Difficulty, &mapShort.Image, &categoryPortal.Category.ID, &categoryPortal.Category.Name, &categoryPortal.PortalCount); err != nil {
614 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 616 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
615 return 617 return
616 } 618 }
diff --git a/backend/handlers/record.go b/backend/handlers/record.go
index bedde57..25a6c6d 100644
--- a/backend/handlers/record.go
+++ b/backend/handlers/record.go
@@ -2,10 +2,8 @@ package handlers
2 2
3import ( 3import (
4 "context" 4 "context"
5 "encoding/base64"
6 "fmt" 5 "fmt"
7 "io" 6 "io"
8 "log"
9 "mime/multipart" 7 "mime/multipart"
10 "net/http" 8 "net/http"
11 "os" 9 "os"
@@ -16,17 +14,14 @@ import (
16 "lphub/models" 14 "lphub/models"
17 "lphub/parser" 15 "lphub/parser"
18 16
17 "github.com/Backblaze/blazer/b2"
19 "github.com/gin-gonic/gin" 18 "github.com/gin-gonic/gin"
20 "github.com/google/uuid" 19 "github.com/google/uuid"
21 "golang.org/x/oauth2/google"
22 "golang.org/x/oauth2/jwt"
23 "google.golang.org/api/drive/v3"
24) 20)
25 21
26type RecordRequest struct { 22type RecordRequest struct {
27 HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"` 23 HostDemo *multipart.FileHeader `json:"host_demo" form:"host_demo" binding:"required" swaggerignore:"true"`
28 PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"` 24 PartnerDemo *multipart.FileHeader `json:"partner_demo" form:"partner_demo" swaggerignore:"true"`
29 PartnerID string `json:"partner_id" form:"partner_id"`
30} 25}
31 26
32type RecordResponse struct { 27type RecordResponse struct {
@@ -79,19 +74,14 @@ func CreateRecordWithDemo(c *gin.Context) {
79 return 74 return
80 } 75 }
81 // Demo files 76 // Demo files
82 demoFiles := []*multipart.FileHeader{record.HostDemo} 77 demoFileHeaders := []*multipart.FileHeader{record.HostDemo}
83 if isCoop { 78 if isCoop {
84 demoFiles = append(demoFiles, record.PartnerDemo) 79 demoFileHeaders = append(demoFileHeaders, record.PartnerDemo)
85 } 80 }
86 var hostDemoUUID, hostDemoFileID, partnerDemoUUID, partnerDemoFileID string 81 var hostDemoUUID, partnerDemoUUID string
87 var hostDemoScoreCount, hostDemoScoreTime int 82 var hostDemoScoreCount, hostDemoScoreTime int
88 var hostSteamID, partnerSteamID string 83 var hostSteamID, partnerSteamID string
89 var hostDemoServerNumber, partnerDemoServerNumber int 84 var hostDemoServerNumber, partnerDemoServerNumber int
90 srv, err := drive.New(serviceAccount())
91 if err != nil {
92 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
93 return
94 }
95 // Create database transaction for inserts 85 // Create database transaction for inserts
96 tx, err := database.DB.Begin() 86 tx, err := database.DB.Begin()
97 if err != nil { 87 if err != nil {
@@ -100,22 +90,16 @@ func CreateRecordWithDemo(c *gin.Context) {
100 } 90 }
101 // Defer to a rollback in case anything fails 91 // Defer to a rollback in case anything fails
102 defer tx.Rollback() 92 defer tx.Rollback()
103 for i, header := range demoFiles { 93 for i, header := range demoFileHeaders {
104 uuid := uuid.New().String() 94 uuid := uuid.New().String()
105 // Upload & insert into demos 95 // Upload & insert into demos
106 err = c.SaveUploadedFile(header, "parser/"+uuid+".dem") 96 f, err := header.Open()
107 if err != nil {
108 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
109 return
110 }
111 defer os.Remove("parser/" + uuid + ".dem")
112 f, err := os.Open("parser/" + uuid + ".dem")
113 if err != nil { 97 if err != nil {
114 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 98 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
115 return 99 return
116 } 100 }
117 defer f.Close() 101 defer f.Close()
118 parserResult, err := parser.ProcessDemo("parser/" + uuid + ".dem") 102 parserResult, err := parser.ProcessDemo(f)
119 if err != nil { 103 if err != nil {
120 c.JSON(http.StatusOK, models.ErrorResponse("Error while processing demo: "+err.Error())) 104 c.JSON(http.StatusOK, models.ErrorResponse("Error while processing demo: "+err.Error()))
121 return 105 return
@@ -148,23 +132,15 @@ func CreateRecordWithDemo(c *gin.Context) {
148 return 132 return
149 } 133 }
150 } 134 }
151 file, err := createFile(srv, uuid+".dem", "application/octet-stream", f, os.Getenv("GOOGLE_FOLDER_ID"))
152 if err != nil {
153 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
154 return
155 }
156 if i == 0 { 135 if i == 0 {
157 hostDemoFileID = file.Id
158 hostDemoUUID = uuid 136 hostDemoUUID = uuid
159 hostDemoServerNumber = parserResult.ServerNumber 137 hostDemoServerNumber = parserResult.ServerNumber
160 } else if i == 1 { 138 } else if i == 1 {
161 partnerDemoFileID = file.Id
162 partnerDemoUUID = uuid 139 partnerDemoUUID = uuid
163 partnerDemoServerNumber = parserResult.ServerNumber 140 partnerDemoServerNumber = parserResult.ServerNumber
164 } 141 }
165 _, err = tx.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) 142 _, err = tx.Exec(`INSERT INTO demos (id) VALUES ($1)`, uuid)
166 if err != nil { 143 if err != nil {
167 deleteFile(srv, file.Id)
168 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 144 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
169 return 145 return
170 } 146 }
@@ -172,8 +148,6 @@ func CreateRecordWithDemo(c *gin.Context) {
172 // Insert into records 148 // Insert into records
173 if isCoop { 149 if isCoop {
174 if hostDemoServerNumber != partnerDemoServerNumber { 150 if hostDemoServerNumber != partnerDemoServerNumber {
175 deleteFile(srv, hostDemoFileID)
176 deleteFile(srv, partnerDemoFileID)
177 c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host and partner demo server numbers (%d & %d) does not match!", hostDemoServerNumber, partnerDemoServerNumber))) 151 c.JSON(http.StatusOK, models.ErrorResponse(fmt.Sprintf("Host and partner demo server numbers (%d & %d) does not match!", hostDemoServerNumber, partnerDemoServerNumber)))
178 return 152 return
179 } 153 }
@@ -192,8 +166,6 @@ func CreateRecordWithDemo(c *gin.Context) {
192 // return 166 // return
193 // } 167 // }
194 if convertedHostSteamID != user.(models.User).SteamID && convertedPartnerSteamID != user.(models.User).SteamID { 168 if convertedHostSteamID != user.(models.User).SteamID && convertedPartnerSteamID != user.(models.User).SteamID {
195 deleteFile(srv, hostDemoFileID)
196 deleteFile(srv, partnerDemoFileID)
197 c.JSON(http.StatusOK, models.ErrorResponse("You are permitted to only upload your own runs!")) 169 c.JSON(http.StatusOK, models.ErrorResponse("You are permitted to only upload your own runs!"))
198 return 170 return
199 } 171 }
@@ -205,8 +177,6 @@ func CreateRecordWithDemo(c *gin.Context) {
205 } 177 }
206 database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", checkPartnerSteamID).Scan(&verifyPartnerSteamID) 178 database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", checkPartnerSteamID).Scan(&verifyPartnerSteamID)
207 if verifyPartnerSteamID != checkPartnerSteamID { 179 if verifyPartnerSteamID != checkPartnerSteamID {
208 deleteFile(srv, hostDemoFileID)
209 deleteFile(srv, partnerDemoFileID)
210 c.JSON(http.StatusOK, models.ErrorResponse("Partner SteamID does not match an account on LPHUB.")) 180 c.JSON(http.StatusOK, models.ErrorResponse("Partner SteamID does not match an account on LPHUB."))
211 return 181 return
212 } 182 }
@@ -214,8 +184,6 @@ func CreateRecordWithDemo(c *gin.Context) {
214 VALUES($1, $2, $3, $4, $5, $6, $7)` 184 VALUES($1, $2, $3, $4, $5, $6, $7)`
215 _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, convertedHostSteamID, convertedPartnerSteamID, hostDemoUUID, partnerDemoUUID) 185 _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, convertedHostSteamID, convertedPartnerSteamID, hostDemoUUID, partnerDemoUUID)
216 if err != nil { 186 if err != nil {
217 deleteFile(srv, hostDemoFileID)
218 deleteFile(srv, partnerDemoFileID)
219 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 187 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
220 return 188 return
221 } 189 }
@@ -224,7 +192,78 @@ func CreateRecordWithDemo(c *gin.Context) {
224 VALUES($1, $2, $3, $4, $5)` 192 VALUES($1, $2, $3, $4, $5)`
225 _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID) 193 _, err := tx.Exec(sql, mapID, hostDemoScoreCount, hostDemoScoreTime, user.(models.User).SteamID, hostDemoUUID)
226 if err != nil { 194 if err != nil {
227 deleteFile(srv, hostDemoFileID) 195 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
196 return
197 }
198 }
199 if os.Getenv("ENV") == "DEV" {
200 if localPath := os.Getenv("LOCAL_DEMOS_PATH"); localPath != "" {
201 for i, header := range demoFileHeaders {
202 f, err := header.Open()
203 if err != nil {
204 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
205 return
206 }
207 defer f.Close()
208 var objectName string
209 if i == 0 {
210 objectName = hostDemoUUID + ".dem"
211 } else if i == 1 {
212 objectName = partnerDemoUUID + ".dem"
213 }
214 demo, err := os.Create(localPath + objectName)
215 if err != nil {
216 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
217 return
218 }
219 defer demo.Close()
220 _, err = io.Copy(demo, f)
221 if err != nil {
222 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
223 return
224 }
225 }
226 if err = tx.Commit(); err != nil {
227 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
228 return
229 }
230 c.JSON(http.StatusOK, models.Response{
231 Success: true,
232 Message: "Successfully created record.",
233 Data: RecordResponse{ScoreCount: hostDemoScoreCount, ScoreTime: hostDemoScoreTime},
234 })
235 return
236 }
237 }
238 // Everything is good, upload the demo files.
239 client, err := b2.NewClient(context.Background(), os.Getenv("B2_KEY_ID"), os.Getenv("B2_API_KEY"))
240 if err != nil {
241 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
242 return
243 }
244 bucket, err := client.Bucket(context.Background(), os.Getenv("B2_BUCKET_NAME"))
245 if err != nil {
246 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
247 return
248 }
249 for i, header := range demoFileHeaders {
250 f, err := header.Open()
251 if err != nil {
252 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
253 return
254 }
255 defer f.Close()
256 var objectName string
257 if i == 0 {
258 objectName = hostDemoUUID + ".dem"
259 } else if i == 1 {
260 objectName = partnerDemoUUID + ".dem"
261 }
262 obj := bucket.Object(objectName)
263 writer := obj.NewWriter(context.Background())
264 defer writer.Close()
265 _, err = io.Copy(writer, f)
266 if err != nil {
228 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 267 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
229 return 268 return
230 } 269 }
@@ -339,91 +378,54 @@ func DownloadDemoWithID(c *gin.Context) {
339 c.JSON(http.StatusOK, models.ErrorResponse("Invalid id given.")) 378 c.JSON(http.StatusOK, models.ErrorResponse("Invalid id given."))
340 return 379 return
341 } 380 }
342 srv, err := drive.New(serviceAccount()) 381 var checkedUUID string
382 err := database.DB.QueryRow("SELECT d.id FROM demos d WHERE d.id = $1", uuid).Scan(&checkedUUID)
343 if err != nil { 383 if err != nil {
344 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 384 c.JSON(http.StatusOK, models.ErrorResponse("Given id does not match a demo."))
345 return 385 return
346 } 386 }
347 387
348 // Query drive instead of finding location id from db because SOMEONE reuploaded the demos. 388 localPath := ""
349 // Tbf I had to reupload and will have to do time after time. Fuck you Google. 389 if os.Getenv("ENV") == "DEV" {
350 // I guess there's no need to store location id of demos anymore? 390 localPath = os.Getenv("LOCAL_DEMOS_PATH")
351 // ALSO ALSO, Google keeps track of old deleted files so sort by createdTime to get the latest demo.
352 fileList, err := srv.Files.List().Q(fmt.Sprintf("name = '%s.dem'", uuid)).
353 Fields("files(id, name, createdTime)").OrderBy("createdTime desc").PageSize(1).Do()
354 if err != nil {
355 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
356 return
357 }
358 if len(fileList.Files) == 0 {
359 c.JSON(http.StatusOK, models.ErrorResponse("Demo not found."))
360 return
361 } 391 }
362 392
363 url := "https://drive.google.com/uc?export=download&id=" + fileList.Files[0].Id
364 fileName := uuid + ".dem" 393 fileName := uuid + ".dem"
365 output, err := os.Create(fileName) 394 if localPath == "" {
366 if err != nil { 395 url := os.Getenv("B2_DOWNLOAD_URL") + fileName
367 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 396 output, err := os.Create(fileName)
368 return 397 if err != nil {
369 } 398 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
370 defer os.Remove(fileName) 399 return
371 defer output.Close() 400 }
372 response, err := http.Get(url) 401 defer os.Remove(fileName)
373 if err != nil { 402 defer output.Close()
374 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 403 response, err := http.Get(url)
375 return 404 if err != nil {
376 } 405 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
377 defer response.Body.Close() 406 return
378 _, err = io.Copy(output, response.Body) 407 }
379 if err != nil { 408 defer response.Body.Close()
380 c.JSON(http.StatusOK, models.ErrorResponse(err.Error())) 409 _, err = io.Copy(output, response.Body)
381 return 410 if err != nil {
411 c.JSON(http.StatusOK, models.ErrorResponse(err.Error()))
412 return
413 }
382 } 414 }
415
383 // Downloaded file 416 // Downloaded file
384 c.Header("Content-Description", "File Transfer") 417 c.Header("Content-Description", "File Transfer")
385 c.Header("Content-Transfer-Encoding", "binary") 418 c.Header("Content-Transfer-Encoding", "binary")
386 c.Header("Content-Disposition", "attachment; filename="+fileName) 419 c.Header("Content-Disposition", "attachment; filename="+fileName)
387 c.Header("Content-Type", "application/octet-stream") 420 c.Header("Content-Type", "application/octet-stream")
388 c.File(fileName)
389 // c.FileAttachment()
390}
391 421
392// Use Service account 422 if localPath == "" {
393func serviceAccount() *http.Client { 423 c.File(fileName)
394 privateKey, _ := base64.StdEncoding.DecodeString(os.Getenv("GOOGLE_PRIVATE_KEY_BASE64")) 424 } else {
395 config := &jwt.Config{ 425 c.File(localPath + fileName)
396 Email: os.Getenv("GOOGLE_CLIENT_EMAIL"),
397 PrivateKey: []byte(privateKey),
398 Scopes: []string{
399 drive.DriveScope,
400 },
401 TokenURL: google.JWTTokenURL,
402 }
403 client := config.Client(context.Background())
404 return client
405}
406
407// Create Gdrive file
408func createFile(service *drive.Service, name string, mimeType string, content io.Reader, parentId string) (*drive.File, error) {
409 f := &drive.File{
410 MimeType: mimeType,
411 Name: name,
412 Parents: []string{parentId},
413 }
414 file, err := service.Files.Create(f).Media(content).Do()
415
416 if err != nil {
417 log.Println("Could not create file: " + err.Error())
418 return nil, err
419 } 426 }
420 427
421 return file, nil 428 // c.FileAttachment()
422}
423
424// Delete Gdrive file
425func deleteFile(service *drive.Service, fileId string) {
426 service.Files.Delete(fileId)
427} 429}
428 430
429// Convert from SteamID64 to Legacy SteamID bits 431// Convert from SteamID64 to Legacy SteamID bits
diff --git a/backend/handlers/user.go b/backend/handlers/user.go
index 53f0d06..ea31065 100644
--- a/backend/handlers/user.go
+++ b/backend/handlers/user.go
@@ -4,6 +4,7 @@ import (
4 "net/http" 4 "net/http"
5 "os" 5 "os"
6 "regexp" 6 "regexp"
7 "sort"
7 "time" 8 "time"
8 9
9 "lphub/database" 10 "lphub/database"
@@ -183,6 +184,15 @@ func Profile(c *gin.Context) {
183 } 184 }
184 } 185 }
185 } 186 }
187 // Sort the overall rankings
188 sort.Slice(rankingsList.Overall, func(i, j int) bool {
189 a := rankingsList.Overall[i]
190 b := rankingsList.Overall[j]
191 if a.TotalScore == b.TotalScore {
192 return a.User.SteamID < b.User.SteamID
193 }
194 return a.TotalScore < b.TotalScore
195 })
186 196
187 placement := 1 197 placement := 1
188 ties := 0 198 ties := 0
@@ -507,6 +517,15 @@ func FetchUser(c *gin.Context) {
507 } 517 }
508 } 518 }
509 } 519 }
520 // Sort the overall rankings
521 sort.Slice(rankingsList.Overall, func(i, j int) bool {
522 a := rankingsList.Overall[i]
523 b := rankingsList.Overall[j]
524 if a.TotalScore == b.TotalScore {
525 return a.User.SteamID < b.User.SteamID
526 }
527 return a.TotalScore < b.TotalScore
528 })
510 529
511 placement := 1 530 placement := 1
512 ties := 0 531 ties := 0
diff --git a/backend/main.go b/backend/main.go
index a1a4a20..e422359 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -11,6 +11,8 @@ import (
11 11
12 "github.com/gin-gonic/gin" 12 "github.com/gin-gonic/gin"
13 "github.com/joho/godotenv" 13 "github.com/joho/godotenv"
14 nrgin "github.com/newrelic/go-agent/v3/integrations/nrgin"
15 "github.com/newrelic/go-agent/v3/newrelic"
14) 16)
15 17
16// @title Least Portals Hub 18// @title Least Portals Hub
@@ -30,7 +32,16 @@ func main() {
30 if os.Getenv("ENV") == "PROD" { 32 if os.Getenv("ENV") == "PROD" {
31 gin.SetMode(gin.ReleaseMode) 33 gin.SetMode(gin.ReleaseMode)
32 } 34 }
35 app, err := newrelic.NewApplication(
36 newrelic.ConfigAppName("lphub"),
37 newrelic.ConfigLicense(os.Getenv("NEWRELIC_LICENSE_KEY")),
38 newrelic.ConfigAppLogForwardingEnabled(true),
39 )
40 if err != nil {
41 log.Fatal("Error instrumenting newrelic")
42 }
33 router := gin.Default() 43 router := gin.Default()
44 router.Use(nrgin.Middleware(app))
34 database.ConnectDB() 45 database.ConnectDB()
35 api.InitRoutes(router) 46 api.InitRoutes(router)
36 // for debugging 47 // for debugging
diff --git a/backend/models/models.go b/backend/models/models.go
index a114f2c..3c38131 100644
--- a/backend/models/models.go
+++ b/backend/models/models.go
@@ -47,6 +47,7 @@ type Map struct {
47 Image string `json:"image"` 47 Image string `json:"image"`
48 IsCoop bool `json:"is_coop"` 48 IsCoop bool `json:"is_coop"`
49 IsDisabled bool `json:"is_disabled"` 49 IsDisabled bool `json:"is_disabled"`
50 Difficulty int `json:"difficulty"`
50} 51}
51 52
52type MapShort struct { 53type MapShort struct {
diff --git a/backend/parser/parser.go b/backend/parser/parser.go
index 19cd677..e39616c 100644
--- a/backend/parser/parser.go
+++ b/backend/parser/parser.go
@@ -2,8 +2,8 @@ package parser
2 2
3import ( 3import (
4 "errors" 4 "errors"
5 "io"
5 "math" 6 "math"
6 "os"
7 "regexp" 7 "regexp"
8 "strconv" 8 "strconv"
9 "strings" 9 "strings"
@@ -22,13 +22,9 @@ type Result struct {
22} 22}
23 23
24// Don't try to understand it, feel it. 24// Don't try to understand it, feel it.
25func ProcessDemo(filePath string) (Result, error) { 25func ProcessDemo(demoFile io.Reader) (Result, error) {
26 var result Result 26 var result Result
27 file, err := os.Open(filePath) 27 reader := bitreader.NewReader(demoFile, true)
28 if err != nil {
29 return Result{}, err
30 }
31 reader := bitreader.NewReader(file, true)
32 demoFileStamp := reader.TryReadString() 28 demoFileStamp := reader.TryReadString()
33 demoProtocol := reader.TryReadSInt32() 29 demoProtocol := reader.TryReadSInt32()
34 networkProtocol := reader.TryReadSInt32() 30 networkProtocol := reader.TryReadSInt32()
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index b342a9c..9ee52eb 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -19,6 +19,7 @@
19 "axios": "^1.7.4", 19 "axios": "^1.7.4",
20 "react": "^18.3.1", 20 "react": "^18.3.1",
21 "react-dom": "^18.3.1", 21 "react-dom": "^18.3.1",
22 "react-helmet": "^6.1.0",
22 "react-markdown": "^9.0.1", 23 "react-markdown": "^9.0.1",
23 "react-router-dom": "^6.26.1", 24 "react-router-dom": "^6.26.1",
24 "react-scripts": "5.0.1", 25 "react-scripts": "5.0.1",
@@ -27,6 +28,7 @@
27 }, 28 },
28 "devDependencies": { 29 "devDependencies": {
29 "@craco/craco": "^7.1.0", 30 "@craco/craco": "^7.1.0",
31 "@types/react-helmet": "^6.1.11",
30 "craco-alias": "^3.0.1" 32 "craco-alias": "^3.0.1"
31 } 33 }
32 }, 34 },
@@ -4302,6 +4304,15 @@
4302 "@types/react": "*" 4304 "@types/react": "*"
4303 } 4305 }
4304 }, 4306 },
4307 "node_modules/@types/react-helmet": {
4308 "version": "6.1.11",
4309 "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz",
4310 "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==",
4311 "dev": true,
4312 "dependencies": {
4313 "@types/react": "*"
4314 }
4315 },
4305 "node_modules/@types/resolve": { 4316 "node_modules/@types/resolve": {
4306 "version": "1.17.1", 4317 "version": "1.17.1",
4307 "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", 4318 "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@@ -15772,6 +15783,25 @@
15772 "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", 15783 "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz",
15773 "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" 15784 "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
15774 }, 15785 },
15786 "node_modules/react-fast-compare": {
15787 "version": "3.2.2",
15788 "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
15789 "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
15790 },
15791 "node_modules/react-helmet": {
15792 "version": "6.1.0",
15793 "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
15794 "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
15795 "dependencies": {
15796 "object-assign": "^4.1.1",
15797 "prop-types": "^15.7.2",
15798 "react-fast-compare": "^3.1.1",
15799 "react-side-effect": "^2.1.0"
15800 },
15801 "peerDependencies": {
15802 "react": ">=16.3.0"
15803 }
15804 },
15775 "node_modules/react-is": { 15805 "node_modules/react-is": {
15776 "version": "17.0.2", 15806 "version": "17.0.2",
15777 "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", 15807 "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -15912,6 +15942,14 @@
15912 } 15942 }
15913 } 15943 }
15914 }, 15944 },
15945 "node_modules/react-side-effect": {
15946 "version": "2.1.2",
15947 "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
15948 "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
15949 "peerDependencies": {
15950 "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
15951 }
15952 },
15915 "node_modules/read-cache": { 15953 "node_modules/read-cache": {
15916 "version": "1.0.0", 15954 "version": "1.0.0",
15917 "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 15955 "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index c317b98..1ee6441 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,6 +14,7 @@
14 "axios": "^1.7.4", 14 "axios": "^1.7.4",
15 "react": "^18.3.1", 15 "react": "^18.3.1",
16 "react-dom": "^18.3.1", 16 "react-dom": "^18.3.1",
17 "react-helmet": "^6.1.0",
17 "react-markdown": "^9.0.1", 18 "react-markdown": "^9.0.1",
18 "react-router-dom": "^6.26.1", 19 "react-router-dom": "^6.26.1",
19 "react-scripts": "5.0.1", 20 "react-scripts": "5.0.1",
@@ -46,6 +47,7 @@
46 }, 47 },
47 "devDependencies": { 48 "devDependencies": {
48 "@craco/craco": "^7.1.0", 49 "@craco/craco": "^7.1.0",
50 "@types/react-helmet": "^6.1.11",
49 "craco-alias": "^3.0.1" 51 "craco-alias": "^3.0.1"
50 } 52 }
51} 53}
diff --git a/frontend/public/index.html b/frontend/public/index.html
index 46a123a..37e27b7 100644
--- a/frontend/public/index.html
+++ b/frontend/public/index.html
@@ -1,21 +1,18 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html lang="en"> 2<html lang="en">
3 <head> 3
4 <meta charset="utf-8" /> 4<head>
5 <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> 5 <meta charset="utf-8" />
6 <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
7 <meta name="theme-color" content="#000000" /> 7 <meta name="viewport" content="width=device-width, initial-scale=1" />
8 <meta 8 <meta name="theme-color" content="#000000" />
9 name="description" 9 <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
10 content="Least Portals Hub" 10 <!--
11 />
12 <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13 <!--
14 manifest.json provides metadata used when your web app is installed on a 11 manifest.json provides metadata used when your web app is installed on a
15 user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ 12 user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16 --> 13 -->
17 <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> 14 <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18 <!-- 15 <!--
19 Notice the use of %PUBLIC_URL% in the tags above. 16 Notice the use of %PUBLIC_URL% in the tags above.
20 It will be replaced with the URL of the `public` folder during the build. 17 It will be replaced with the URL of the `public` folder during the build.
21 Only files inside the `public` folder can be referenced from the HTML. 18 Only files inside the `public` folder can be referenced from the HTML.
@@ -24,12 +21,13 @@
24 work correctly both with client-side routing and a non-root public URL. 21 work correctly both with client-side routing and a non-root public URL.
25 Learn how to configure a non-root public URL by running `npm run build`. 22 Learn how to configure a non-root public URL by running `npm run build`.
26 --> 23 -->
27 <title>Least Portals Hub</title> 24 <title>LPHUB</title>
28 </head> 25</head>
29 <body> 26
30 <noscript>You need to enable JavaScript to run this app.</noscript> 27<body>
31 <div id="root"></div> 28 <noscript>You need to enable JavaScript to run this app.</noscript>
32 <!-- 29 <div id="root"></div>
30 <!--
33 This HTML file is a template. 31 This HTML file is a template.
34 If you open it directly in the browser, you will see an empty page. 32 If you open it directly in the browser, you will see an empty page.
35 33
@@ -39,5 +37,6 @@
39 To begin the development, run `npm start` or `yarn start`. 37 To begin the development, run `npm start` or `yarn start`.
40 To create a production bundle, use `npm run build` or `yarn build`. 38 To create a production bundle, use `npm run build` or `yarn build`.
41 --> 39 -->
42 </body> 40</body>
43</html> 41
42</html> \ No newline at end of file
diff --git a/frontend/public/response.json b/frontend/public/response.json
deleted file mode 100644
index a2f3190..0000000
--- a/frontend/public/response.json
+++ /dev/null
@@ -1,4984 +0,0 @@
1{
2 "success": true,
3 "message": "Successfully retrieved rankings.",
4 "data": {
5 "rankings_singleplayer": [
6 {
7 "user_name": "SuperAiderton",
8 "avatar_link": "https://avatars.steamstatic.com/a19aca196dbb75b51b83fe7d06b0b7fce0f894b2_full.jpg",
9 "steam_id": "76561199069631083",
10 "sp_score": 65,
11 "mp_score": 48,
12 "overall_score": 113,
13 "sp_rank": 1,
14 "mp_rank": 7,
15 "overall_rank": 1
16 },
17 {
18 "user_name": "GLaBOSS",
19 "avatar_link": "https://avatars.steamstatic.com/9adb9839e82a9d8506e80d6436f9af08f4202ba4_full.jpg",
20 "steam_id": "76561198069545076",
21 "sp_score": 72,
22 "mp_score": 0,
23 "overall_score": 0,
24 "sp_rank": 2,
25 "mp_rank": 0,
26 "overall_rank": 0
27 },
28 {
29 "user_name": "zombotany2",
30 "avatar_link": "https://avatars.steamstatic.com/1a23caeff548e3683db8880bf48882bd9cc0e348_full.jpg",
31 "steam_id": "76561198084336096",
32 "sp_score": 72,
33 "mp_score": 2,
34 "overall_score": 0,
35 "sp_rank": 2,
36 "mp_rank": 0,
37 "overall_rank": 0
38 },
39 {
40 "user_name": "mOtYl",
41 "avatar_link": "https://avatars.steamstatic.com/8065f6018757dc0ee927d2279ccf7e8ab7827109_full.jpg",
42 "steam_id": "76561197994700458",
43 "sp_score": 74,
44 "mp_score": 49,
45 "overall_score": 123,
46 "sp_rank": 3,
47 "mp_rank": 8,
48 "overall_rank": 3
49 },
50 {
51 "user_name": "Nidboj132",
52 "avatar_link": "https://avatars.steamstatic.com/07bc99e768c9f640979e2a393f28306a32fa796e_full.jpg",
53 "steam_id": "76561198337970645",
54 "sp_score": 76,
55 "mp_score": 41,
56 "overall_score": 117,
57 "sp_rank": 4,
58 "mp_rank": 1,
59 "overall_rank": 2
60 },
61 {
62 "user_name": "Thearus",
63 "avatar_link": "https://avatars.steamstatic.com/06175d3938f1203e80bcbf5898d7ca803e7555eb_full.jpg",
64 "steam_id": "76561198846409182",
65 "sp_score": 79,
66 "mp_score": 50,
67 "overall_score": 0,
68 "sp_rank": 5,
69 "mp_rank": 0,
70 "overall_rank": 0
71 },
72 {
73 "user_name": "?",
74 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
75 "steam_id": "76561198838630481",
76 "sp_score": 80,
77 "mp_score": 46,
78 "overall_score": 126,
79 "sp_rank": 6,
80 "mp_rank": 5,
81 "overall_rank": 4
82 },
83 {
84 "user_name": "slamix",
85 "avatar_link": "https://avatars.steamstatic.com/730aee7d3904a0f38506858ba83ebc014260ccc3_full.jpg",
86 "steam_id": "76561198403952785",
87 "sp_score": 81,
88 "mp_score": 47,
89 "overall_score": 128,
90 "sp_rank": 7,
91 "mp_rank": 6,
92 "overall_rank": 6
93 },
94 {
95 "user_name": "xeonic",
96 "avatar_link": "https://avatars.steamstatic.com/7c3e67f433c90512fe6cac7278d6cb8b59d10c96_full.jpg",
97 "steam_id": "76561198973478625",
98 "sp_score": 82,
99 "mp_score": 45,
100 "overall_score": 127,
101 "sp_rank": 8,
102 "mp_rank": 4,
103 "overall_rank": 5
104 },
105 {
106 "user_name": "PerOculos",
107 "avatar_link": "https://avatars.steamstatic.com/7b00906ac356806bc7bdb3815ea7c1c5b13b65a8_full.jpg",
108 "steam_id": "76561198003223063",
109 "sp_score": 84,
110 "mp_score": 50,
111 "overall_score": 134,
112 "sp_rank": 9,
113 "mp_rank": 9,
114 "overall_rank": 8
115 },
116 {
117 "user_name": "Black_Semka",
118 "avatar_link": "https://avatars.steamstatic.com/3a6acf4e40097d9db7af432684a08b6267d2af5c_full.jpg",
119 "steam_id": "76561198997027314",
120 "sp_score": 85,
121 "mp_score": 41,
122 "overall_score": 126,
123 "sp_rank": 10,
124 "mp_rank": 1,
125 "overall_rank": 4
126 },
127 {
128 "user_name": "LittleRoi",
129 "avatar_link": "https://avatars.steamstatic.com/c9180f93ac892fa7d078f5946239d049e987e3b6_full.jpg",
130 "steam_id": "76561198112477703",
131 "sp_score": 85,
132 "mp_score": 50,
133 "overall_score": 135,
134 "sp_rank": 10,
135 "mp_rank": 9,
136 "overall_rank": 9
137 },
138 {
139 "user_name": "Robotwars1",
140 "avatar_link": "https://avatars.steamstatic.com/ac4bc6cc73ef75f11690205b123685fd5e3a7823_full.jpg",
141 "steam_id": "76561198129010912",
142 "sp_score": 86,
143 "mp_score": 49,
144 "overall_score": 135,
145 "sp_rank": 11,
146 "mp_rank": 8,
147 "overall_rank": 9
148 },
149 {
150 "user_name": "MrCatMcFly",
151 "avatar_link": "https://avatars.steamstatic.com/6f89591012f8f0f34cef1ecdb1c10793b0ea4bd1_full.jpg",
152 "steam_id": "76561198168920589",
153 "sp_score": 87,
154 "mp_score": 66,
155 "overall_score": 153,
156 "sp_rank": 12,
157 "mp_rank": 25,
158 "overall_rank": 20
159 },
160 {
161 "user_name": "BiSaXa",
162 "avatar_link": "https://avatars.steamstatic.com/fa7f64c79b247c8a80cafbd6dd8033b98cc1153c_full.jpg",
163 "steam_id": "76561198131629989",
164 "sp_score": 87,
165 "mp_score": 47,
166 "overall_score": 134,
167 "sp_rank": 12,
168 "mp_rank": 6,
169 "overall_rank": 8
170 },
171 {
172 "user_name": "shred",
173 "avatar_link": "https://avatars.steamstatic.com/0216ce300d00ec193414773679db7dcd77d1cd29_full.jpg",
174 "steam_id": "76561198025486280",
175 "sp_score": 88,
176 "mp_score": 59,
177 "overall_score": 147,
178 "sp_rank": 13,
179 "mp_rank": 18,
180 "overall_rank": 15
181 },
182 {
183 "user_name": "Krzyhau",
184 "avatar_link": "https://avatars.steamstatic.com/f29de7f41db29526848b52c8942f727b7c70b0db_full.jpg",
185 "steam_id": "76561198096446735",
186 "sp_score": 89,
187 "mp_score": 52,
188 "overall_score": 141,
189 "sp_rank": 14,
190 "mp_rank": 11,
191 "overall_rank": 12
192 },
193 {
194 "user_name": "SrRageALot",
195 "avatar_link": "https://avatars.steamstatic.com/db9c6b6761d63c640456043d864f98f58f62d750_full.jpg",
196 "steam_id": "76561199156418931",
197 "sp_score": 89,
198 "mp_score": 57,
199 "overall_score": 146,
200 "sp_rank": 14,
201 "mp_rank": 16,
202 "overall_rank": 14
203 },
204 {
205 "user_name": "Feirune~",
206 "avatar_link": "https://avatars.steamstatic.com/fece8c2b7c57f3eecf75897ad86609adefb7ec1a_full.jpg",
207 "steam_id": "76561198134041367",
208 "sp_score": 90,
209 "mp_score": 41,
210 "overall_score": 131,
211 "sp_rank": 15,
212 "mp_rank": 1,
213 "overall_rank": 7
214 },
215 {
216 "user_name": "TeePeeWee",
217 "avatar_link": "https://avatars.steamstatic.com/4392a52e384f22c9f77b539eb4b1aa2914880cdf_full.jpg",
218 "steam_id": "76561199239427541",
219 "sp_score": 90,
220 "mp_score": 48,
221 "overall_score": 138,
222 "sp_rank": 15,
223 "mp_rank": 7,
224 "overall_rank": 10
225 },
226 {
227 "user_name": "(MGN)-ZGP-NIKITA",
228 "avatar_link": "https://avatars.steamstatic.com/8a72e1ed5a29e56c24926ccb33879a544bc67b36_full.jpg",
229 "steam_id": "76561198076017585",
230 "sp_score": 91,
231 "mp_score": 49,
232 "overall_score": 140,
233 "sp_rank": 16,
234 "mp_rank": 8,
235 "overall_rank": 11
236 },
237 {
238 "user_name": "Confusion_18",
239 "avatar_link": "https://avatars.steamstatic.com/360236e555049f204b12d3a8685a3b9b9764ebfe_full.jpg",
240 "steam_id": "76561198386577258",
241 "sp_score": 91,
242 "mp_score": 51,
243 "overall_score": 142,
244 "sp_rank": 16,
245 "mp_rank": 10,
246 "overall_rank": 13
247 },
248 {
249 "user_name": "Linus",
250 "avatar_link": "https://avatars.steamstatic.com/cfaf6917f47ca6122396f46e485a79a090f29fa0_full.jpg",
251 "steam_id": "76561198162078579",
252 "sp_score": 92,
253 "mp_score": 49,
254 "overall_score": 141,
255 "sp_rank": 17,
256 "mp_rank": 8,
257 "overall_rank": 12
258 },
259 {
260 "user_name": "Zadadaz",
261 "avatar_link": "https://avatars.steamstatic.com/8c7bed09ce10417502477b6ca29f8257c840cab3_full.jpg",
262 "steam_id": "76561198451680661",
263 "sp_score": 92,
264 "mp_score": 43,
265 "overall_score": 135,
266 "sp_rank": 17,
267 "mp_rank": 2,
268 "overall_rank": 9
269 },
270 {
271 "user_name": "マジックサラダ",
272 "avatar_link": "https://avatars.steamstatic.com/8772186a3ab48712b6eb955a46d269b52ebda706_full.jpg",
273 "steam_id": "76561198092289827",
274 "sp_score": 93,
275 "mp_score": 55,
276 "overall_score": 148,
277 "sp_rank": 18,
278 "mp_rank": 14,
279 "overall_rank": 16
280 },
281 {
282 "user_name": "cubone",
283 "avatar_link": "https://avatars.steamstatic.com/e285359230318e5cfb27ed688903c5350cd21075_full.jpg",
284 "steam_id": "76561198096862334",
285 "sp_score": 93,
286 "mp_score": 59,
287 "overall_score": 152,
288 "sp_rank": 18,
289 "mp_rank": 18,
290 "overall_rank": 19
291 },
292 {
293 "user_name": "KnightedNave",
294 "avatar_link": "https://avatars.steamstatic.com/7f03558f490c8418c7864da9eb9eac8579485758_full.jpg",
295 "steam_id": "76561199164989405",
296 "sp_score": 94,
297 "mp_score": 190,
298 "overall_score": 0,
299 "sp_rank": 19,
300 "mp_rank": 0,
301 "overall_rank": 0
302 },
303 {
304 "user_name": "unity",
305 "avatar_link": "https://avatars.steamstatic.com/1fcc7701ff71dce31965e10408d79aeb79bdf051_full.jpg",
306 "steam_id": "76561198081168311",
307 "sp_score": 96,
308 "mp_score": 53,
309 "overall_score": 149,
310 "sp_rank": 20,
311 "mp_rank": 12,
312 "overall_rank": 17
313 },
314 {
315 "user_name": "niceeggtryingtime",
316 "avatar_link": "https://avatars.steamstatic.com/4120dc145e5b5b4dcb37a47bd2f4cb04b56e6481_full.jpg",
317 "steam_id": "76561199139116725",
318 "sp_score": 97,
319 "mp_score": 0,
320 "overall_score": 0,
321 "sp_rank": 21,
322 "mp_rank": 0,
323 "overall_rank": 0
324 },
325 {
326 "user_name": "Suola",
327 "avatar_link": "https://avatars.steamstatic.com/f86dcc2d065a87a603427bb382d26e96c1d61060_full.jpg",
328 "steam_id": "76561198917972968",
329 "sp_score": 98,
330 "mp_score": 50,
331 "overall_score": 148,
332 "sp_rank": 22,
333 "mp_rank": 9,
334 "overall_rank": 16
335 },
336 {
337 "user_name": "Pr0tal",
338 "avatar_link": "https://avatars.steamstatic.com/ce72799aa2cf4b591df09b3afc715b2259963af7_full.jpg",
339 "steam_id": "76561198292863694",
340 "sp_score": 98,
341 "mp_score": 68,
342 "overall_score": 166,
343 "sp_rank": 22,
344 "mp_rank": 27,
345 "overall_rank": 26
346 },
347 {
348 "user_name": "Herneerius",
349 "avatar_link": "https://avatars.steamstatic.com/4879fa1c72770b2c0eaef341dc6546db13897bb5_full.jpg",
350 "steam_id": "76561198084978888",
351 "sp_score": 98,
352 "mp_score": 61,
353 "overall_score": 159,
354 "sp_rank": 22,
355 "mp_rank": 20,
356 "overall_rank": 22
357 },
358 {
359 "user_name": "Burger40",
360 "avatar_link": "https://avatars.steamstatic.com/00db94cf7b185c69936738b5a827c63d033c6479_full.jpg",
361 "steam_id": "76561198083196477",
362 "sp_score": 98,
363 "mp_score": 66,
364 "overall_score": 164,
365 "sp_rank": 22,
366 "mp_rank": 25,
367 "overall_rank": 25
368 },
369 {
370 "user_name": "Extension",
371 "avatar_link": "https://avatars.steamstatic.com/dbaf3958fffebf266ce5c04316da744987e9b1fb_full.jpg",
372 "steam_id": "76561199221334063",
373 "sp_score": 99,
374 "mp_score": 61,
375 "overall_score": 160,
376 "sp_rank": 23,
377 "mp_rank": 20,
378 "overall_rank": 23
379 },
380 {
381 "user_name": "nnsega",
382 "avatar_link": "https://avatars.steamstatic.com/3443fd796fa8fd5169990b919238c663662e9fa8_full.jpg",
383 "steam_id": "76561198979969586",
384 "sp_score": 99,
385 "mp_score": 0,
386 "overall_score": 0,
387 "sp_rank": 23,
388 "mp_rank": 0,
389 "overall_rank": 0
390 },
391 {
392 "user_name": "Pizza2002com",
393 "avatar_link": "https://avatars.steamstatic.com/ed56a1d461c7a9e9ad5343c352020bc420bcc412_full.jpg",
394 "steam_id": "76561198198438581",
395 "sp_score": 100,
396 "mp_score": 9,
397 "overall_score": 0,
398 "sp_rank": 24,
399 "mp_rank": 0,
400 "overall_rank": 0
401 },
402 {
403 "user_name": "Imagine a cool name",
404 "avatar_link": "https://avatars.steamstatic.com/ed6186b9c575f4df60c138785c9c004ad9bd4fae_full.jpg",
405 "steam_id": "76561198869299905",
406 "sp_score": 101,
407 "mp_score": 71,
408 "overall_score": 172,
409 "sp_rank": 25,
410 "mp_rank": 30,
411 "overall_rank": 30
412 },
413 {
414 "user_name": "BLAZEICN",
415 "avatar_link": "https://avatars.steamstatic.com/fc6db63846adac48e89c2a22148d8eb8cf3fdc50_full.jpg",
416 "steam_id": "76561198410217177",
417 "sp_score": 102,
418 "mp_score": 59,
419 "overall_score": 0,
420 "sp_rank": 26,
421 "mp_rank": 0,
422 "overall_rank": 0
423 },
424 {
425 "user_name": "Toast",
426 "avatar_link": "https://avatars.steamstatic.com/c66f54f744f4a0dd0b09fbf8a587959a99025d7e_full.jpg",
427 "steam_id": "76561198064751325",
428 "sp_score": 104,
429 "mp_score": 71,
430 "overall_score": 0,
431 "sp_rank": 27,
432 "mp_rank": 0,
433 "overall_rank": 0
434 },
435 {
436 "user_name": "Smily Dog",
437 "avatar_link": "https://avatars.steamstatic.com/721fc92c86478824e0f9768320ce65324d44bd64_full.jpg",
438 "steam_id": "76561199069689933",
439 "sp_score": 105,
440 "mp_score": 196,
441 "overall_score": 0,
442 "sp_rank": 28,
443 "mp_rank": 0,
444 "overall_rank": 0
445 },
446 {
447 "user_name": "Zypeh",
448 "avatar_link": "https://avatars.steamstatic.com/bfd2b759e7e6300fc709857b9e6db802084544d1_full.jpg",
449 "steam_id": "76561198039230536",
450 "sp_score": 106,
451 "mp_score": 55,
452 "overall_score": 161,
453 "sp_rank": 29,
454 "mp_rank": 14,
455 "overall_rank": 24
456 },
457 {
458 "user_name": "AngerySnek",
459 "avatar_link": "https://avatars.steamstatic.com/36f5af69d7f5763b4fbede1c3a067f97505e77ce_full.jpg",
460 "steam_id": "76561198149112443",
461 "sp_score": 106,
462 "mp_score": 107,
463 "overall_score": 0,
464 "sp_rank": 29,
465 "mp_rank": 0,
466 "overall_rank": 0
467 },
468 {
469 "user_name": "Iniquitty",
470 "avatar_link": "https://avatars.steamstatic.com/5c6c4e6b58ebd8a57db8305465398d33f017d125_full.jpg",
471 "steam_id": "76561198048252922",
472 "sp_score": 106,
473 "mp_score": 181,
474 "overall_score": 0,
475 "sp_rank": 29,
476 "mp_rank": 0,
477 "overall_rank": 0
478 },
479 {
480 "user_name": "NeKz",
481 "avatar_link": "https://avatars.steamstatic.com/9a86e6554aee395b3ac37d96a808335363eb79ff_full.jpg",
482 "steam_id": "76561198049848090",
483 "sp_score": 107,
484 "mp_score": 57,
485 "overall_score": 164,
486 "sp_rank": 30,
487 "mp_rank": 16,
488 "overall_rank": 25
489 },
490 {
491 "user_name": "Jarool",
492 "avatar_link": "https://avatars.steamstatic.com/61bb4ee9a8dd6cef5427f2170bb75d3162f3c8e8_full.jpg",
493 "steam_id": "76561198021055079",
494 "sp_score": 107,
495 "mp_score": 59,
496 "overall_score": 166,
497 "sp_rank": 30,
498 "mp_rank": 18,
499 "overall_rank": 26
500 },
501 {
502 "user_name": "bob26798",
503 "avatar_link": "https://avatars.steamstatic.com/cb940cd751f980d8d1374a66118a43f19985a1fa_full.jpg",
504 "steam_id": "76561198278905764",
505 "sp_score": 107,
506 "mp_score": 51,
507 "overall_score": 158,
508 "sp_rank": 30,
509 "mp_rank": 10,
510 "overall_rank": 21
511 },
512 {
513 "user_name": "Extension",
514 "avatar_link": "https://avatars.steamstatic.com/a647685b273a238928180573feb8135944d2795c_full.jpg",
515 "steam_id": "76561198174735211",
516 "sp_score": 108,
517 "mp_score": 51,
518 "overall_score": 159,
519 "sp_rank": 31,
520 "mp_rank": 10,
521 "overall_rank": 22
522 },
523 {
524 "user_name": "felkelorebel",
525 "avatar_link": "https://avatars.steamstatic.com/b3745dd64d516fb7ce7072aaad09c93fd99c48f5_full.jpg",
526 "steam_id": "76561198015394804",
527 "sp_score": 108,
528 "mp_score": 43,
529 "overall_score": 151,
530 "sp_rank": 31,
531 "mp_rank": 2,
532 "overall_rank": 18
533 },
534 {
535 "user_name": "fullheart2",
536 "avatar_link": "https://avatars.steamstatic.com/1daea993c3be4435d49bc50f7b011d639a08f3c9_full.jpg",
537 "steam_id": "76561197997838862",
538 "sp_score": 108,
539 "mp_score": 53,
540 "overall_score": 161,
541 "sp_rank": 31,
542 "mp_rank": 12,
543 "overall_rank": 24
544 },
545 {
546 "user_name": "Daddy Sparky420",
547 "avatar_link": "https://avatars.steamstatic.com/14bd5c9bee517058bed74638465e5f68f8ce1d68_full.jpg",
548 "steam_id": "76561198044110926",
549 "sp_score": 108,
550 "mp_score": 52,
551 "overall_score": 160,
552 "sp_rank": 31,
553 "mp_rank": 11,
554 "overall_rank": 23
555 },
556 {
557 "user_name": "HighOfSolipsism",
558 "avatar_link": "https://avatars.steamstatic.com/fb4b381574521f30828684ba8fbf328d5d179909_full.jpg",
559 "steam_id": "76561198968889092",
560 "sp_score": 109,
561 "mp_score": 0,
562 "overall_score": 0,
563 "sp_rank": 32,
564 "mp_rank": 0,
565 "overall_rank": 0
566 },
567 {
568 "user_name": "Lowengeist",
569 "avatar_link": "https://avatars.steamstatic.com/4f9a9168c48434a27dfe32d5831ce9fdcfb3ed96_full.jpg",
570 "steam_id": "76561198122276362",
571 "sp_score": 110,
572 "mp_score": 51,
573 "overall_score": 161,
574 "sp_rank": 33,
575 "mp_rank": 10,
576 "overall_rank": 24
577 },
578 {
579 "user_name": "Leve",
580 "avatar_link": "https://avatars.steamstatic.com/7a56621890546d1a54d4b583198b4d30411950b2_full.jpg",
581 "steam_id": "76561198902321340",
582 "sp_score": 111,
583 "mp_score": 60,
584 "overall_score": 171,
585 "sp_rank": 34,
586 "mp_rank": 19,
587 "overall_rank": 29
588 },
589 {
590 "user_name": "Jess3n",
591 "avatar_link": "https://avatars.steamstatic.com/1ee47a4ad1a50a4307cde6a9c543b3207942596c_full.jpg",
592 "steam_id": "76561198870020820",
593 "sp_score": 112,
594 "mp_score": 58,
595 "overall_score": 170,
596 "sp_rank": 35,
597 "mp_rank": 17,
598 "overall_rank": 28
599 },
600 {
601 "user_name": "UrMomPlebLol",
602 "avatar_link": "https://avatars.steamstatic.com/5b5b9357badc3d9e9ba53d52cf851a85df4a910c_full.jpg",
603 "steam_id": "76561198371482646",
604 "sp_score": 112,
605 "mp_score": 73,
606 "overall_score": 185,
607 "sp_rank": 35,
608 "mp_rank": 32,
609 "overall_rank": 38
610 },
611 {
612 "user_name": "stip",
613 "avatar_link": "https://avatars.steamstatic.com/19be8fd7d791a14920566ce35cc2798ecda8a9e4_full.jpg",
614 "steam_id": "76561198238515424",
615 "sp_score": 113,
616 "mp_score": 63,
617 "overall_score": 176,
618 "sp_rank": 36,
619 "mp_rank": 22,
620 "overall_rank": 32
621 },
622 {
623 "user_name": "False",
624 "avatar_link": "https://avatars.steamstatic.com/37269283113d026dc07f892792d5d2e413632047_full.jpg",
625 "steam_id": "76561198880435416",
626 "sp_score": 114,
627 "mp_score": 104,
628 "overall_score": 0,
629 "sp_rank": 37,
630 "mp_rank": 0,
631 "overall_rank": 0
632 },
633 {
634 "user_name": "Fridge",
635 "avatar_link": "https://avatars.steamstatic.com/ba9584900b25936d72bd8b7fb028eea0b0d0fa56_full.jpg",
636 "steam_id": "76561198367132611",
637 "sp_score": 115,
638 "mp_score": 51,
639 "overall_score": 166,
640 "sp_rank": 38,
641 "mp_rank": 10,
642 "overall_rank": 26
643 },
644 {
645 "user_name": "Throw",
646 "avatar_link": "https://avatars.steamstatic.com/2c01a87d1b0789f7bdd1f3e693ef9987e49abe01_full.jpg",
647 "steam_id": "76561198952505877",
648 "sp_score": 115,
649 "mp_score": 78,
650 "overall_score": 193,
651 "sp_rank": 38,
652 "mp_rank": 36,
653 "overall_rank": 42
654 },
655 {
656 "user_name": "MarvelousBilly",
657 "avatar_link": "https://avatars.steamstatic.com/199a06d3111cec6ae8fa5fa118b4569ea4ed35d0_full.jpg",
658 "steam_id": "76561198207042355",
659 "sp_score": 115,
660 "mp_score": 64,
661 "overall_score": 0,
662 "sp_rank": 38,
663 "mp_rank": 0,
664 "overall_rank": 0
665 },
666 {
667 "user_name": "timurkazz",
668 "avatar_link": "https://avatars.steamstatic.com/13f6adfa0189055299b1ed69418eec8dd3b5d9eb_full.jpg",
669 "steam_id": "76561199106449775",
670 "sp_score": 115,
671 "mp_score": 53,
672 "overall_score": 168,
673 "sp_rank": 38,
674 "mp_rank": 12,
675 "overall_rank": 27
676 },
677 {
678 "user_name": "Morality",
679 "avatar_link": "https://avatars.steamstatic.com/2ea3e5885aa789acfc3640788905a414c408edc9_full.jpg",
680 "steam_id": "76561198799058701",
681 "sp_score": 115,
682 "mp_score": 53,
683 "overall_score": 168,
684 "sp_rank": 38,
685 "mp_rank": 12,
686 "overall_rank": 27
687 },
688 {
689 "user_name": "Yugge",
690 "avatar_link": "https://avatars.steamstatic.com/dc7c081330432a22b2d44cca2c02285c3ad04813_full.jpg",
691 "steam_id": "76561198405615224",
692 "sp_score": 117,
693 "mp_score": 63,
694 "overall_score": 180,
695 "sp_rank": 39,
696 "mp_rank": 22,
697 "overall_rank": 36
698 },
699 {
700 "user_name": "LsDK_",
701 "avatar_link": "https://avatars.steamstatic.com/4bf97c27bd5824296c0dedd11f5da1b2f0cdb7a5_full.jpg",
702 "steam_id": "76561198103821970",
703 "sp_score": 117,
704 "mp_score": 47,
705 "overall_score": 164,
706 "sp_rank": 39,
707 "mp_rank": 6,
708 "overall_rank": 25
709 },
710 {
711 "user_name": "j_p_smith",
712 "avatar_link": "https://avatars.steamstatic.com/1522b5cd27f52fde1326a5dc68980ae8a7a68f77_full.jpg",
713 "steam_id": "76561198845788732",
714 "sp_score": 117,
715 "mp_score": 9,
716 "overall_score": 0,
717 "sp_rank": 39,
718 "mp_rank": 0,
719 "overall_rank": 0
720 },
721 {
722 "user_name": "ThatGoatWhoIsEpic",
723 "avatar_link": "https://avatars.steamstatic.com/5049e37e3b511134a4a1b8359a8103348c09ff17_full.jpg",
724 "steam_id": "76561198074525881",
725 "sp_score": 117,
726 "mp_score": 72,
727 "overall_score": 189,
728 "sp_rank": 39,
729 "mp_rank": 31,
730 "overall_rank": 40
731 },
732 {
733 "user_name": "nintendude",
734 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
735 "steam_id": "76561198307085542",
736 "sp_score": 118,
737 "mp_score": 54,
738 "overall_score": 172,
739 "sp_rank": 40,
740 "mp_rank": 13,
741 "overall_rank": 30
742 },
743 {
744 "user_name": "bubblebuddy",
745 "avatar_link": "https://avatars.steamstatic.com/087e1fd15b96879183296125bdd3976ac715c746_full.jpg",
746 "steam_id": "76561198076502234",
747 "sp_score": 118,
748 "mp_score": 91,
749 "overall_score": 0,
750 "sp_rank": 40,
751 "mp_rank": 0,
752 "overall_rank": 0
753 },
754 {
755 "user_name": "Shiro",
756 "avatar_link": "https://avatars.steamstatic.com/7160e03d7c638627813e5fb993bf921c828b02c2_full.jpg",
757 "steam_id": "76561198118924124",
758 "sp_score": 119,
759 "mp_score": 55,
760 "overall_score": 174,
761 "sp_rank": 41,
762 "mp_rank": 14,
763 "overall_rank": 31
764 },
765 {
766 "user_name": "ุ",
767 "avatar_link": "https://avatars.steamstatic.com/b698f81978cd408b5e210f5b5c09d308ae75165b_full.jpg",
768 "steam_id": "76561198200883819",
769 "sp_score": 121,
770 "mp_score": 64,
771 "overall_score": 185,
772 "sp_rank": 42,
773 "mp_rank": 23,
774 "overall_rank": 38
775 },
776 {
777 "user_name": "Chevalix",
778 "avatar_link": "https://avatars.steamstatic.com/db8a0073f499823d0fb4ba89ee8716971a321a4e_full.jpg",
779 "steam_id": "76561198302681368",
780 "sp_score": 121,
781 "mp_score": 58,
782 "overall_score": 179,
783 "sp_rank": 42,
784 "mp_rank": 17,
785 "overall_rank": 35
786 },
787 {
788 "user_name": "Snow",
789 "avatar_link": "https://avatars.steamstatic.com/64b513f2c1f8a490670aa3d004d71b95207035b8_full.jpg",
790 "steam_id": "76561198842803939",
791 "sp_score": 121,
792 "mp_score": 56,
793 "overall_score": 177,
794 "sp_rank": 42,
795 "mp_rank": 15,
796 "overall_rank": 33
797 },
798 {
799 "user_name": "AMJ",
800 "avatar_link": "https://avatars.steamstatic.com/43480cfa66f1b35c2098016221a4dc19ed4fab55_full.jpg",
801 "steam_id": "76561198067936604",
802 "sp_score": 121,
803 "mp_score": 57,
804 "overall_score": 178,
805 "sp_rank": 42,
806 "mp_rank": 16,
807 "overall_rank": 34
808 },
809 {
810 "user_name": "turkey",
811 "avatar_link": "https://avatars.steamstatic.com/82d4da8f4ebd2022d32520c48554f05847e278d2_full.jpg",
812 "steam_id": "76561199175950732",
813 "sp_score": 123,
814 "mp_score": 112,
815 "overall_score": 0,
816 "sp_rank": 43,
817 "mp_rank": 0,
818 "overall_rank": 0
819 },
820 {
821 "user_name": "100kitaizzev",
822 "avatar_link": "https://avatars.steamstatic.com/93c7cb31e2b51e636e308788c7264b70e9756c9d_full.jpg",
823 "steam_id": "76561198006939388",
824 "sp_score": 123,
825 "mp_score": 65,
826 "overall_score": 188,
827 "sp_rank": 43,
828 "mp_rank": 24,
829 "overall_rank": 39
830 },
831 {
832 "user_name": "h@iku",
833 "avatar_link": "https://avatars.steamstatic.com/bfb0f0be647a28135ba306cd2e40c6ece3ca11b2_full.jpg",
834 "steam_id": "76561198343098423",
835 "sp_score": 123,
836 "mp_score": 55,
837 "overall_score": 178,
838 "sp_rank": 43,
839 "mp_rank": 14,
840 "overall_rank": 34
841 },
842 {
843 "user_name": "SPLOTH",
844 "avatar_link": "https://avatars.steamstatic.com/186537343f416a3562aefc53ec6a31e064da5f3b_full.jpg",
845 "steam_id": "76561199551856036",
846 "sp_score": 124,
847 "mp_score": 0,
848 "overall_score": 0,
849 "sp_rank": 44,
850 "mp_rank": 0,
851 "overall_rank": 0
852 },
853 {
854 "user_name": "Flaming Bag of Shit",
855 "avatar_link": "https://avatars.steamstatic.com/1aa57ae65716c4e6110f625d070a7d8e9d96953f_full.jpg",
856 "steam_id": "76561198118049581",
857 "sp_score": 124,
858 "mp_score": 58,
859 "overall_score": 0,
860 "sp_rank": 44,
861 "mp_rank": 0,
862 "overall_rank": 0
863 },
864 {
865 "user_name": "Jerms",
866 "avatar_link": "https://avatars.steamstatic.com/6c6f26b05c96e83ee326033e5a60837c38230c82_full.jpg",
867 "steam_id": "76561198185044258",
868 "sp_score": 125,
869 "mp_score": 127,
870 "overall_score": 0,
871 "sp_rank": 45,
872 "mp_rank": 0,
873 "overall_rank": 0
874 },
875 {
876 "user_name": "Moon",
877 "avatar_link": "https://avatars.steamstatic.com/8dfe278c7493b6984540e57ecd57b791df13841e_full.jpg",
878 "steam_id": "76561198202772881",
879 "sp_score": 126,
880 "mp_score": 91,
881 "overall_score": 0,
882 "sp_rank": 46,
883 "mp_rank": 0,
884 "overall_rank": 0
885 },
886 {
887 "user_name": "JonVis",
888 "avatar_link": "https://avatars.steamstatic.com/67cda3d7d1764089ddf51dc3413846b0042cc04f_full.jpg",
889 "steam_id": "76561198331042729",
890 "sp_score": 127,
891 "mp_score": 219,
892 "overall_score": 0,
893 "sp_rank": 47,
894 "mp_rank": 0,
895 "overall_rank": 0
896 },
897 {
898 "user_name": "matchafluff",
899 "avatar_link": "https://avatars.steamstatic.com/ccef93cdccb9555781530303010a1bba551066a5_full.jpg",
900 "steam_id": "76561198274451918",
901 "sp_score": 128,
902 "mp_score": 0,
903 "overall_score": 0,
904 "sp_rank": 48,
905 "mp_rank": 0,
906 "overall_rank": 0
907 },
908 {
909 "user_name": "Waygric",
910 "avatar_link": "https://avatars.steamstatic.com/99a1312a700f85059c38d40235c98498accd7e12_full.jpg",
911 "steam_id": "76561198295161335",
912 "sp_score": 129,
913 "mp_score": 152,
914 "overall_score": 0,
915 "sp_rank": 49,
916 "mp_rank": 0,
917 "overall_rank": 0
918 },
919 {
920 "user_name": "edcr",
921 "avatar_link": "https://avatars.steamstatic.com/f77b7721e8bab560dfc04164001771654265d48f_full.jpg",
922 "steam_id": "76561198254824137",
923 "sp_score": 130,
924 "mp_score": 0,
925 "overall_score": 0,
926 "sp_rank": 50,
927 "mp_rank": 0,
928 "overall_rank": 0
929 },
930 {
931 "user_name": "lampishboi",
932 "avatar_link": "https://avatars.steamstatic.com/22bc948278437707cf69cc70a153f8363c95bccf_full.jpg",
933 "steam_id": "76561198994808916",
934 "sp_score": 131,
935 "mp_score": 199,
936 "overall_score": 330,
937 "sp_rank": 51,
938 "mp_rank": 81,
939 "overall_rank": 61
940 },
941 {
942 "user_name": "jarmge",
943 "avatar_link": "https://avatars.steamstatic.com/600e01f106f252ed8ca1dabfcab6fbb1b036bfc6_full.jpg",
944 "steam_id": "76561198169932919",
945 "sp_score": 132,
946 "mp_score": 64,
947 "overall_score": 0,
948 "sp_rank": 52,
949 "mp_rank": 0,
950 "overall_rank": 0
951 },
952 {
953 "user_name": "Spyrunite",
954 "avatar_link": "https://avatars.steamstatic.com/184e99f06e36b81346214c37f6b448f4d71fcb8b_full.jpg",
955 "steam_id": "76561198026851335",
956 "sp_score": 132,
957 "mp_score": 98,
958 "overall_score": 230,
959 "sp_rank": 52,
960 "mp_rank": 50,
961 "overall_rank": 52
962 },
963 {
964 "user_name": "danybanana",
965 "avatar_link": "https://avatars.steamstatic.com/0c2c9ee032d40f217feba46a7d592dd6e69a1cc1_full.jpg",
966 "steam_id": "76561198111286521",
967 "sp_score": 133,
968 "mp_score": 233,
969 "overall_score": 0,
970 "sp_rank": 53,
971 "mp_rank": 0,
972 "overall_rank": 0
973 },
974 {
975 "user_name": "Rubiks37",
976 "avatar_link": "https://avatars.steamstatic.com/fc56ec380897e968373ada65084d8c1527b9d408_full.jpg",
977 "steam_id": "76561198246124618",
978 "sp_score": 133,
979 "mp_score": 98,
980 "overall_score": 0,
981 "sp_rank": 53,
982 "mp_rank": 0,
983 "overall_rank": 0
984 },
985 {
986 "user_name": "Palmer",
987 "avatar_link": "https://avatars.steamstatic.com/cb2cb750f2601cd3d44941babe87638e49d5f0f5_full.jpg",
988 "steam_id": "76561198047887079",
989 "sp_score": 133,
990 "mp_score": 0,
991 "overall_score": 0,
992 "sp_rank": 53,
993 "mp_rank": 0,
994 "overall_rank": 0
995 },
996 {
997 "user_name": "XTLmaker",
998 "avatar_link": "https://avatars.steamstatic.com/b3c041f3eb316e0edf16e6ba36f426b433e16cee_full.jpg",
999 "steam_id": "76561199032030834",
1000 "sp_score": 134,
1001 "mp_score": 97,
1002 "overall_score": 231,
1003 "sp_rank": 54,
1004 "mp_rank": 49,
1005 "overall_rank": 53
1006 },
1007 {
1008 "user_name": "real",
1009 "avatar_link": "https://avatars.steamstatic.com/be7eec8a60d692720284391b078383d970e3e4c1_full.jpg",
1010 "steam_id": "76561198810570115",
1011 "sp_score": 135,
1012 "mp_score": 0,
1013 "overall_score": 0,
1014 "sp_rank": 55,
1015 "mp_rank": 0,
1016 "overall_rank": 0
1017 },
1018 {
1019 "user_name": "FifthWit",
1020 "avatar_link": "https://avatars.steamstatic.com/e5e291a0cd9af9e3dd86b1a1610cca9381714f6b_full.jpg",
1021 "steam_id": "76561197992325624",
1022 "sp_score": 135,
1023 "mp_score": 218,
1024 "overall_score": 0,
1025 "sp_rank": 55,
1026 "mp_rank": 0,
1027 "overall_rank": 0
1028 },
1029 {
1030 "user_name": "Paurel009",
1031 "avatar_link": "https://avatars.steamstatic.com/332bc892f89dd38c8a4821057ef6c79d9217a00f_full.jpg",
1032 "steam_id": "76561198879028282",
1033 "sp_score": 135,
1034 "mp_score": 56,
1035 "overall_score": 0,
1036 "sp_rank": 55,
1037 "mp_rank": 0,
1038 "overall_rank": 0
1039 },
1040 {
1041 "user_name": "badger",
1042 "avatar_link": "https://avatars.steamstatic.com/cbea4cfe87dab41ed9d2b53be876110b98e4111a_full.jpg",
1043 "steam_id": "76561198861024091",
1044 "sp_score": 135,
1045 "mp_score": 89,
1046 "overall_score": 224,
1047 "sp_rank": 55,
1048 "mp_rank": 43,
1049 "overall_rank": 50
1050 },
1051 {
1052 "user_name": "Soulfur",
1053 "avatar_link": "https://avatars.steamstatic.com/af59571446fe62756d619b9e42a82c432390ccf0_full.jpg",
1054 "steam_id": "76561198181126266",
1055 "sp_score": 135,
1056 "mp_score": 56,
1057 "overall_score": 191,
1058 "sp_rank": 55,
1059 "mp_rank": 15,
1060 "overall_rank": 41
1061 },
1062 {
1063 "user_name": "Kitsune",
1064 "avatar_link": "https://avatars.steamstatic.com/20bd0d2ff33f74c95500c5d11d4b550aa04fe505_full.jpg",
1065 "steam_id": "76561198136477838",
1066 "sp_score": 136,
1067 "mp_score": 48,
1068 "overall_score": 184,
1069 "sp_rank": 56,
1070 "mp_rank": 7,
1071 "overall_rank": 37
1072 },
1073 {
1074 "user_name": "SmileyCraft",
1075 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
1076 "steam_id": "76561198040989295",
1077 "sp_score": 136,
1078 "mp_score": 0,
1079 "overall_score": 0,
1080 "sp_rank": 56,
1081 "mp_rank": 0,
1082 "overall_rank": 0
1083 },
1084 {
1085 "user_name": "1 Portal SWAG",
1086 "avatar_link": "https://avatars.steamstatic.com/8766c163ce9fd7a584c5347dab0a6a49766102e8_full.jpg",
1087 "steam_id": "76561198253811824",
1088 "sp_score": 137,
1089 "mp_score": 82,
1090 "overall_score": 219,
1091 "sp_rank": 57,
1092 "mp_rank": 39,
1093 "overall_rank": 49
1094 },
1095 {
1096 "user_name": "William",
1097 "avatar_link": "https://avatars.steamstatic.com/72789abfbdf55ae8e229c9782c871d8a90bb783b_full.jpg",
1098 "steam_id": "76561198255055970",
1099 "sp_score": 137,
1100 "mp_score": 0,
1101 "overall_score": 0,
1102 "sp_rank": 57,
1103 "mp_rank": 0,
1104 "overall_rank": 0
1105 },
1106 {
1107 "user_name": "MegaWaTT",
1108 "avatar_link": "https://avatars.steamstatic.com/ed56d8fc9c49a77d3f8c8bd6cc3efa72e714b54d_full.jpg",
1109 "steam_id": "76561198363863187",
1110 "sp_score": 137,
1111 "mp_score": 92,
1112 "overall_score": 229,
1113 "sp_rank": 57,
1114 "mp_rank": 45,
1115 "overall_rank": 51
1116 },
1117 {
1118 "user_name": "LinuxCat",
1119 "avatar_link": "https://avatars.steamstatic.com/8232b8f0813332e141ebd63cadc5223f3f4571e8_full.jpg",
1120 "steam_id": "76561198430886429",
1121 "sp_score": 138,
1122 "mp_score": 166,
1123 "overall_score": 0,
1124 "sp_rank": 58,
1125 "mp_rank": 0,
1126 "overall_rank": 0
1127 },
1128 {
1129 "user_name": "Domitar1",
1130 "avatar_link": "https://avatars.steamstatic.com/24566e2b3ee69e45d4fa23e783d7b655893ee36e_full.jpg",
1131 "steam_id": "76561198036153876",
1132 "sp_score": 139,
1133 "mp_score": 67,
1134 "overall_score": 0,
1135 "sp_rank": 59,
1136 "mp_rank": 0,
1137 "overall_rank": 0
1138 },
1139 {
1140 "user_name": "Scanner Man",
1141 "avatar_link": "https://avatars.steamstatic.com/17a6dfe85895df9afaf653b937bc7594e43c310a_full.jpg",
1142 "steam_id": "76561198453234651",
1143 "sp_score": 139,
1144 "mp_score": 0,
1145 "overall_score": 0,
1146 "sp_rank": 59,
1147 "mp_rank": 0,
1148 "overall_rank": 0
1149 },
1150 {
1151 "user_name": "austamate17",
1152 "avatar_link": "https://avatars.steamstatic.com/545cb42d2650240f0c4dec95a4132cb7cc1593f9_full.jpg",
1153 "steam_id": "76561199134645248",
1154 "sp_score": 139,
1155 "mp_score": 174,
1156 "overall_score": 0,
1157 "sp_rank": 59,
1158 "mp_rank": 0,
1159 "overall_rank": 0
1160 },
1161 {
1162 "user_name": "indexsensei",
1163 "avatar_link": "https://avatars.steamstatic.com/d27a4396b3b9c98a1a349d9e9fc3b08a1c70e0ab_full.jpg",
1164 "steam_id": "76561199505740367",
1165 "sp_score": 140,
1166 "mp_score": 0,
1167 "overall_score": 0,
1168 "sp_rank": 60,
1169 "mp_rank": 0,
1170 "overall_rank": 0
1171 },
1172 {
1173 "user_name": "KranK",
1174 "avatar_link": "https://avatars.steamstatic.com/4adacf733ceac099fd425172813d7162723746aa_full.jpg",
1175 "steam_id": "76561198044394357",
1176 "sp_score": 140,
1177 "mp_score": 0,
1178 "overall_score": 0,
1179 "sp_rank": 60,
1180 "mp_rank": 0,
1181 "overall_rank": 0
1182 },
1183 {
1184 "user_name": "Mayor of Kenja",
1185 "avatar_link": "https://avatars.steamstatic.com/e15d3d3912851067482704cf50d3e692b21fe252_full.jpg",
1186 "steam_id": "76561198041107150",
1187 "sp_score": 141,
1188 "mp_score": 101,
1189 "overall_score": 0,
1190 "sp_rank": 61,
1191 "mp_rank": 0,
1192 "overall_rank": 0
1193 },
1194 {
1195 "user_name": "Myhr",
1196 "avatar_link": "https://avatars.steamstatic.com/deec440da6c13c8fa72f003d8396c15d6238c89e_full.jpg",
1197 "steam_id": "76561198054566481",
1198 "sp_score": 141,
1199 "mp_score": 52,
1200 "overall_score": 193,
1201 "sp_rank": 61,
1202 "mp_rank": 11,
1203 "overall_rank": 42
1204 },
1205 {
1206 "user_name": "Fyrestorm",
1207 "avatar_link": "https://avatars.steamstatic.com/c0c82fa70c986348caaaea71f3ccac1b13c0c4eb_full.jpg",
1208 "steam_id": "76561198035761863",
1209 "sp_score": 142,
1210 "mp_score": 55,
1211 "overall_score": 197,
1212 "sp_rank": 62,
1213 "mp_rank": 14,
1214 "overall_rank": 43
1215 },
1216 {
1217 "user_name": "Turmoil",
1218 "avatar_link": "https://avatars.steamstatic.com/ceeb79bfd441b1928af34195dfde660b44f002dd_full.jpg",
1219 "steam_id": "76561197997770103",
1220 "sp_score": 142,
1221 "mp_score": 57,
1222 "overall_score": 199,
1223 "sp_rank": 62,
1224 "mp_rank": 16,
1225 "overall_rank": 44
1226 },
1227 {
1228 "user_name": "SilentiumGradas",
1229 "avatar_link": "https://avatars.steamstatic.com/b26b46bc2dd6efece8b6cbcff8ba263801b5b6dc_full.jpg",
1230 "steam_id": "76561199006050430",
1231 "sp_score": 142,
1232 "mp_score": 101,
1233 "overall_score": 243,
1234 "sp_rank": 62,
1235 "mp_rank": 51,
1236 "overall_rank": 55
1237 },
1238 {
1239 "user_name": "elvirus21",
1240 "avatar_link": "https://avatars.steamstatic.com/f91787b7fb6d4a2cb8dee079ab457839b33a8845_full.jpg",
1241 "steam_id": "76561198073106572",
1242 "sp_score": 142,
1243 "mp_score": 7,
1244 "overall_score": 0,
1245 "sp_rank": 62,
1246 "mp_rank": 0,
1247 "overall_rank": 0
1248 },
1249 {
1250 "user_name": "Piguy922",
1251 "avatar_link": "https://avatars.steamstatic.com/d4fbe6b8c96fd091c5ffb154486e68517bdfa0a9_full.jpg",
1252 "steam_id": "76561198286556924",
1253 "sp_score": 142,
1254 "mp_score": 0,
1255 "overall_score": 0,
1256 "sp_rank": 62,
1257 "mp_rank": 0,
1258 "overall_rank": 0
1259 },
1260 {
1261 "user_name": "Rubix",
1262 "avatar_link": "https://avatars.steamstatic.com/968068f38b0b1cbfa81003eb0b30616ccaf22074_full.jpg",
1263 "steam_id": "76561199038050237",
1264 "sp_score": 143,
1265 "mp_score": 0,
1266 "overall_score": 0,
1267 "sp_rank": 63,
1268 "mp_rank": 0,
1269 "overall_rank": 0
1270 },
1271 {
1272 "user_name": "Stitch",
1273 "avatar_link": "https://avatars.steamstatic.com/1db7a665ec08caf5924fa3f85a94f563308186ba_full.jpg",
1274 "steam_id": "76561198210115312",
1275 "sp_score": 144,
1276 "mp_score": 0,
1277 "overall_score": 0,
1278 "sp_rank": 64,
1279 "mp_rank": 0,
1280 "overall_rank": 0
1281 },
1282 {
1283 "user_name": "Blenderiste09",
1284 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
1285 "steam_id": "76561198251755710",
1286 "sp_score": 145,
1287 "mp_score": 56,
1288 "overall_score": 201,
1289 "sp_rank": 65,
1290 "mp_rank": 15,
1291 "overall_rank": 45
1292 },
1293 {
1294 "user_name": "Schwi",
1295 "avatar_link": "https://avatars.steamstatic.com/a5ab762db09205fc49a6fa8fd1d09daafc3ac6e4_full.jpg",
1296 "steam_id": "76561198384377251",
1297 "sp_score": 147,
1298 "mp_score": 69,
1299 "overall_score": 216,
1300 "sp_rank": 66,
1301 "mp_rank": 28,
1302 "overall_rank": 48
1303 },
1304 {
1305 "user_name": "Simmo",
1306 "avatar_link": "https://avatars.steamstatic.com/e12f942704510e129880a683efe61a38f771d5b3_full.jpg",
1307 "steam_id": "76561198018586508",
1308 "sp_score": 147,
1309 "mp_score": 198,
1310 "overall_score": 0,
1311 "sp_rank": 66,
1312 "mp_rank": 0,
1313 "overall_rank": 0
1314 },
1315 {
1316 "user_name": "laredeshot",
1317 "avatar_link": "https://avatars.steamstatic.com/8ffb58e0cddad5293c48250deb458f428b9f6736_full.jpg",
1318 "steam_id": "76561198261656551",
1319 "sp_score": 149,
1320 "mp_score": 56,
1321 "overall_score": 205,
1322 "sp_rank": 67,
1323 "mp_rank": 15,
1324 "overall_rank": 46
1325 },
1326 {
1327 "user_name": "Jenga World Champion",
1328 "avatar_link": "https://avatars.steamstatic.com/fcf3c636e29e074a5d58ceb1929f12e8f35f7b20_full.jpg",
1329 "steam_id": "76561197995200743",
1330 "sp_score": 151,
1331 "mp_score": 0,
1332 "overall_score": 0,
1333 "sp_rank": 68,
1334 "mp_rank": 0,
1335 "overall_rank": 0
1336 },
1337 {
1338 "user_name": "Tenacite the MAD Milshake",
1339 "avatar_link": "https://avatars.steamstatic.com/dc22cc282f8bd43f3efde936b7263130f09358b8_full.jpg",
1340 "steam_id": "76561198389681125",
1341 "sp_score": 152,
1342 "mp_score": 49,
1343 "overall_score": 201,
1344 "sp_rank": 69,
1345 "mp_rank": 8,
1346 "overall_rank": 45
1347 },
1348 {
1349 "user_name": "Betsruner",
1350 "avatar_link": "https://avatars.steamstatic.com/6e5b5f43361149652d556073c34a4c3bd5c56df2_full.jpg",
1351 "steam_id": "76561198048179892",
1352 "sp_score": 153,
1353 "mp_score": 113,
1354 "overall_score": 266,
1355 "sp_rank": 70,
1356 "mp_rank": 57,
1357 "overall_rank": 58
1358 },
1359 {
1360 "user_name": "Vyolet",
1361 "avatar_link": "https://avatars.steamstatic.com/c70dfe3d294d9967f0fe623495939fda03afecd1_full.jpg",
1362 "steam_id": "76561198865544248",
1363 "sp_score": 154,
1364 "mp_score": 257,
1365 "overall_score": 0,
1366 "sp_rank": 71,
1367 "mp_rank": 0,
1368 "overall_rank": 0
1369 },
1370 {
1371 "user_name": "fatman",
1372 "avatar_link": "https://avatars.steamstatic.com/eb327dec91a694f5fc4f789857bc92ac2e881867_full.jpg",
1373 "steam_id": "76561198148419890",
1374 "sp_score": 155,
1375 "mp_score": 162,
1376 "overall_score": 0,
1377 "sp_rank": 72,
1378 "mp_rank": 0,
1379 "overall_rank": 0
1380 },
1381 {
1382 "user_name": "Saxton Hale",
1383 "avatar_link": "https://avatars.steamstatic.com/2f335962fbb8431ea3f5606fe3e1881dce47e63a_full.jpg",
1384 "steam_id": "76561197998253566",
1385 "sp_score": 155,
1386 "mp_score": 75,
1387 "overall_score": 230,
1388 "sp_rank": 72,
1389 "mp_rank": 34,
1390 "overall_rank": 52
1391 },
1392 {
1393 "user_name": "Orange",
1394 "avatar_link": "https://avatars.steamstatic.com/af229251379e11527a25aed1a896c83730c7c216_full.jpg",
1395 "steam_id": "76561198240558232",
1396 "sp_score": 156,
1397 "mp_score": 107,
1398 "overall_score": 0,
1399 "sp_rank": 73,
1400 "mp_rank": 0,
1401 "overall_rank": 0
1402 },
1403 {
1404 "user_name": "savvydruid",
1405 "avatar_link": "https://avatars.steamstatic.com/687d290c9238b42a790216892cc21f718741bd83_full.jpg",
1406 "steam_id": "76561199013726692",
1407 "sp_score": 157,
1408 "mp_score": 53,
1409 "overall_score": 210,
1410 "sp_rank": 74,
1411 "mp_rank": 12,
1412 "overall_rank": 47
1413 },
1414 {
1415 "user_name": "『 Jonese1234 』",
1416 "avatar_link": "https://avatars.steamstatic.com/9f6de098624a8f81ba6d2318e1923bdda1c710d6_full.jpg",
1417 "steam_id": "76561198045074889",
1418 "sp_score": 157,
1419 "mp_score": 206,
1420 "overall_score": 363,
1421 "sp_rank": 74,
1422 "mp_rank": 85,
1423 "overall_rank": 62
1424 },
1425 {
1426 "user_name": "ki4rakaM [RUS]",
1427 "avatar_link": "https://avatars.steamstatic.com/cae7d5a1e4b04f70dc0c1599d932edb423e65870_full.jpg",
1428 "steam_id": "76561198227911092",
1429 "sp_score": 157,
1430 "mp_score": 89,
1431 "overall_score": 246,
1432 "sp_rank": 74,
1433 "mp_rank": 43,
1434 "overall_rank": 56
1435 },
1436 {
1437 "user_name": "Jythonscript",
1438 "avatar_link": "https://avatars.steamstatic.com/a158a5eeb8fbb49c8ba626fb99dc2bdf44052dc0_full.jpg",
1439 "steam_id": "76561198165015808",
1440 "sp_score": 159,
1441 "mp_score": 16,
1442 "overall_score": 0,
1443 "sp_rank": 75,
1444 "mp_rank": 0,
1445 "overall_rank": 0
1446 },
1447 {
1448 "user_name": "meatslab",
1449 "avatar_link": "https://avatars.steamstatic.com/c3b05a2f6c9e7c51c2314d984bf03ac5ddec8c96_full.jpg",
1450 "steam_id": "76561197993087239",
1451 "sp_score": 159,
1452 "mp_score": 201,
1453 "overall_score": 0,
1454 "sp_rank": 75,
1455 "mp_rank": 0,
1456 "overall_rank": 0
1457 },
1458 {
1459 "user_name": "berlinkijalapinio",
1460 "avatar_link": "https://avatars.steamstatic.com/31bca616d9bad59e446995159f3198bc131be2af_full.jpg",
1461 "steam_id": "76561199026933461",
1462 "sp_score": 159,
1463 "mp_score": 0,
1464 "overall_score": 0,
1465 "sp_rank": 75,
1466 "mp_rank": 0,
1467 "overall_rank": 0
1468 },
1469 {
1470 "user_name": "Wrath",
1471 "avatar_link": "https://avatars.steamstatic.com/da6a4f2a804e8fd4bce38efc5b7f256f964a3fb7_full.jpg",
1472 "steam_id": "76561197983206857",
1473 "sp_score": 161,
1474 "mp_score": 47,
1475 "overall_score": 0,
1476 "sp_rank": 76,
1477 "mp_rank": 0,
1478 "overall_rank": 0
1479 },
1480 {
1481 "user_name": "Schlepian",
1482 "avatar_link": "https://avatars.steamstatic.com/f7be9949784d7864c619a72e0bec1138a14933ff_full.jpg",
1483 "steam_id": "76561198021734854",
1484 "sp_score": 161,
1485 "mp_score": 105,
1486 "overall_score": 266,
1487 "sp_rank": 76,
1488 "mp_rank": 52,
1489 "overall_rank": 58
1490 },
1491 {
1492 "user_name": "Pongu",
1493 "avatar_link": "https://avatars.steamstatic.com/c65e60109bc9e6fc7143de48fddb7aac812f4b54_full.jpg",
1494 "steam_id": "76561199092053226",
1495 "sp_score": 163,
1496 "mp_score": 0,
1497 "overall_score": 0,
1498 "sp_rank": 77,
1499 "mp_rank": 0,
1500 "overall_rank": 0
1501 },
1502 {
1503 "user_name": "gate",
1504 "avatar_link": "https://avatars.steamstatic.com/26458ac0a9e4a290b2edc09801b09e92ab74a747_full.jpg",
1505 "steam_id": "76561199070019903",
1506 "sp_score": 164,
1507 "mp_score": 156,
1508 "overall_score": 0,
1509 "sp_rank": 78,
1510 "mp_rank": 0,
1511 "overall_rank": 0
1512 },
1513 {
1514 "user_name": "Lathil",
1515 "avatar_link": "https://avatars.steamstatic.com/6636331f0f7d69a2ef6557a124ae4a3389466047_full.jpg",
1516 "steam_id": "76561198404861950",
1517 "sp_score": 165,
1518 "mp_score": 59,
1519 "overall_score": 224,
1520 "sp_rank": 79,
1521 "mp_rank": 18,
1522 "overall_rank": 50
1523 },
1524 {
1525 "user_name": "ZeroKage69",
1526 "avatar_link": "https://avatars.steamstatic.com/46d3dc44a52ce13feeb11f9174a3df192e281d79_full.jpg",
1527 "steam_id": "76561198000282331",
1528 "sp_score": 168,
1529 "mp_score": 0,
1530 "overall_score": 0,
1531 "sp_rank": 80,
1532 "mp_rank": 0,
1533 "overall_rank": 0
1534 },
1535 {
1536 "user_name": "TacoCat1717",
1537 "avatar_link": "https://avatars.steamstatic.com/3a80d39cbb425d5a1847578f2cfef504e51df744_full.jpg",
1538 "steam_id": "76561198353761498",
1539 "sp_score": 169,
1540 "mp_score": 0,
1541 "overall_score": 0,
1542 "sp_rank": 81,
1543 "mp_rank": 0,
1544 "overall_rank": 0
1545 },
1546 {
1547 "user_name": "Imanex",
1548 "avatar_link": "https://avatars.steamstatic.com/82d1ac52aeddb7f08eb0f85d4f7d96160af30bb9_full.jpg",
1549 "steam_id": "76561197974616889",
1550 "sp_score": 169,
1551 "mp_score": 82,
1552 "overall_score": 251,
1553 "sp_rank": 81,
1554 "mp_rank": 39,
1555 "overall_rank": 57
1556 },
1557 {
1558 "user_name": "Schlay",
1559 "avatar_link": "https://avatars.steamstatic.com/1c81f34080417cab9a836c003e5c319229e528f9_full.jpg",
1560 "steam_id": "76561198042995537",
1561 "sp_score": 170,
1562 "mp_score": 108,
1563 "overall_score": 278,
1564 "sp_rank": 82,
1565 "mp_rank": 53,
1566 "overall_rank": 59
1567 },
1568 {
1569 "user_name": "¯\\_(ツ)_/¯",
1570 "avatar_link": "https://avatars.steamstatic.com/fb9c36c36e54b8ca5f2e1cbd89c06574d1348af0_full.jpg",
1571 "steam_id": "76561198001523094",
1572 "sp_score": 175,
1573 "mp_score": 127,
1574 "overall_score": 302,
1575 "sp_rank": 83,
1576 "mp_rank": 64,
1577 "overall_rank": 60
1578 },
1579 {
1580 "user_name": "wol",
1581 "avatar_link": "https://avatars.steamstatic.com/689a4b1be66db3f28a1567c7b1bb7e8e2d1e1d90_full.jpg",
1582 "steam_id": "76561199007976762",
1583 "sp_score": 177,
1584 "mp_score": 57,
1585 "overall_score": 234,
1586 "sp_rank": 84,
1587 "mp_rank": 16,
1588 "overall_rank": 54
1589 },
1590 {
1591 "user_name": "omni-",
1592 "avatar_link": "https://avatars.steamstatic.com/080a99bb24dd24c3e0d898e844e5579ac3d11467_full.jpg",
1593 "steam_id": "76561198188030349",
1594 "sp_score": 181,
1595 "mp_score": 52,
1596 "overall_score": 0,
1597 "sp_rank": 85,
1598 "mp_rank": 0,
1599 "overall_rank": 0
1600 },
1601 {
1602 "user_name": "Ragnar",
1603 "avatar_link": "https://avatars.steamstatic.com/cb0b6e7874c36bd65143bfce9c1f77723d0128bb_full.jpg",
1604 "steam_id": "76561198018384094",
1605 "sp_score": 184,
1606 "mp_score": 92,
1607 "overall_score": 0,
1608 "sp_rank": 86,
1609 "mp_rank": 0,
1610 "overall_rank": 0
1611 },
1612 {
1613 "user_name": "Iijil",
1614 "avatar_link": "https://avatars.steamstatic.com/2bdb2025ffcf3f0a12a716260c7308a9f7a15c3c_full.jpg",
1615 "steam_id": "76561197970963482",
1616 "sp_score": 194,
1617 "mp_score": 0,
1618 "overall_score": 0,
1619 "sp_rank": 87,
1620 "mp_rank": 0,
1621 "overall_rank": 0
1622 },
1623 {
1624 "user_name": "HuskyManiac",
1625 "avatar_link": "https://avatars.steamstatic.com/d63d68bc5ae49161d044a3ea8f93d78d5a0be840_full.jpg",
1626 "steam_id": "76561199137138817",
1627 "sp_score": 203,
1628 "mp_score": 162,
1629 "overall_score": 0,
1630 "sp_rank": 88,
1631 "mp_rank": 0,
1632 "overall_rank": 0
1633 },
1634 {
1635 "user_name": "Potatoes",
1636 "avatar_link": "https://avatars.steamstatic.com/94821c98d19e5eda6ec315289aa28b191084f301_full.jpg",
1637 "steam_id": "76561197974561284",
1638 "sp_score": 248,
1639 "mp_score": 209,
1640 "overall_score": 457,
1641 "sp_rank": 89,
1642 "mp_rank": 88,
1643 "overall_rank": 63
1644 }
1645 ],
1646 "rankings_multiplayer": [
1647 {
1648 "user_name": "Nidboj132",
1649 "avatar_link": "https://avatars.steamstatic.com/07bc99e768c9f640979e2a393f28306a32fa796e_full.jpg",
1650 "steam_id": "76561198337970645",
1651 "sp_score": 76,
1652 "mp_score": 41,
1653 "overall_score": 117,
1654 "sp_rank": 4,
1655 "mp_rank": 1,
1656 "overall_rank": 2
1657 },
1658 {
1659 "user_name": "Black_Semka",
1660 "avatar_link": "https://avatars.steamstatic.com/3a6acf4e40097d9db7af432684a08b6267d2af5c_full.jpg",
1661 "steam_id": "76561198997027314",
1662 "sp_score": 85,
1663 "mp_score": 41,
1664 "overall_score": 126,
1665 "sp_rank": 10,
1666 "mp_rank": 1,
1667 "overall_rank": 4
1668 },
1669 {
1670 "user_name": "Feirune~",
1671 "avatar_link": "https://avatars.steamstatic.com/fece8c2b7c57f3eecf75897ad86609adefb7ec1a_full.jpg",
1672 "steam_id": "76561198134041367",
1673 "sp_score": 90,
1674 "mp_score": 41,
1675 "overall_score": 131,
1676 "sp_rank": 15,
1677 "mp_rank": 1,
1678 "overall_rank": 7
1679 },
1680 {
1681 "user_name": "felkelorebel",
1682 "avatar_link": "https://avatars.steamstatic.com/b3745dd64d516fb7ce7072aaad09c93fd99c48f5_full.jpg",
1683 "steam_id": "76561198015394804",
1684 "sp_score": 108,
1685 "mp_score": 43,
1686 "overall_score": 151,
1687 "sp_rank": 31,
1688 "mp_rank": 2,
1689 "overall_rank": 18
1690 },
1691 {
1692 "user_name": "Zadadaz",
1693 "avatar_link": "https://avatars.steamstatic.com/8c7bed09ce10417502477b6ca29f8257c840cab3_full.jpg",
1694 "steam_id": "76561198451680661",
1695 "sp_score": 92,
1696 "mp_score": 43,
1697 "overall_score": 135,
1698 "sp_rank": 17,
1699 "mp_rank": 2,
1700 "overall_rank": 9
1701 },
1702 {
1703 "user_name": "RealCreative",
1704 "avatar_link": "https://avatars.steamstatic.com/ace8efdb0d060e2bbc8d9d210429fbfea6d247e5_full.jpg",
1705 "steam_id": "76561198823602829",
1706 "sp_score": 140,
1707 "mp_score": 44,
1708 "overall_score": 0,
1709 "sp_rank": 0,
1710 "mp_rank": 3,
1711 "overall_rank": 0
1712 },
1713 {
1714 "user_name": "xeonic",
1715 "avatar_link": "https://avatars.steamstatic.com/7c3e67f433c90512fe6cac7278d6cb8b59d10c96_full.jpg",
1716 "steam_id": "76561198973478625",
1717 "sp_score": 82,
1718 "mp_score": 45,
1719 "overall_score": 127,
1720 "sp_rank": 8,
1721 "mp_rank": 4,
1722 "overall_rank": 5
1723 },
1724 {
1725 "user_name": "?",
1726 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
1727 "steam_id": "76561198838630481",
1728 "sp_score": 80,
1729 "mp_score": 46,
1730 "overall_score": 126,
1731 "sp_rank": 6,
1732 "mp_rank": 5,
1733 "overall_rank": 4
1734 },
1735 {
1736 "user_name": "No Name",
1737 "avatar_link": "https://avatars.steamstatic.com/2d070642c13b83f2218ada99aed9be26af3653e4_full.jpg",
1738 "steam_id": "76561198278611000",
1739 "sp_score": 1,
1740 "mp_score": 46,
1741 "overall_score": 0,
1742 "sp_rank": 0,
1743 "mp_rank": 5,
1744 "overall_rank": 0
1745 },
1746 {
1747 "user_name": "3e0r",
1748 "avatar_link": "https://avatars.steamstatic.com/c8405cf90fdbfccf8f7b22f09cb0444737ddec5f_full.jpg",
1749 "steam_id": "76561199067727348",
1750 "sp_score": 109,
1751 "mp_score": 47,
1752 "overall_score": 0,
1753 "sp_rank": 0,
1754 "mp_rank": 6,
1755 "overall_rank": 0
1756 },
1757 {
1758 "user_name": "LsDK_",
1759 "avatar_link": "https://avatars.steamstatic.com/4bf97c27bd5824296c0dedd11f5da1b2f0cdb7a5_full.jpg",
1760 "steam_id": "76561198103821970",
1761 "sp_score": 117,
1762 "mp_score": 47,
1763 "overall_score": 164,
1764 "sp_rank": 39,
1765 "mp_rank": 6,
1766 "overall_rank": 25
1767 },
1768 {
1769 "user_name": "slamix",
1770 "avatar_link": "https://avatars.steamstatic.com/730aee7d3904a0f38506858ba83ebc014260ccc3_full.jpg",
1771 "steam_id": "76561198403952785",
1772 "sp_score": 81,
1773 "mp_score": 47,
1774 "overall_score": 128,
1775 "sp_rank": 7,
1776 "mp_rank": 6,
1777 "overall_rank": 6
1778 },
1779 {
1780 "user_name": "BiSaXa",
1781 "avatar_link": "https://avatars.steamstatic.com/fa7f64c79b247c8a80cafbd6dd8033b98cc1153c_full.jpg",
1782 "steam_id": "76561198131629989",
1783 "sp_score": 87,
1784 "mp_score": 47,
1785 "overall_score": 134,
1786 "sp_rank": 12,
1787 "mp_rank": 6,
1788 "overall_rank": 8
1789 },
1790 {
1791 "user_name": "SuperAiderton",
1792 "avatar_link": "https://avatars.steamstatic.com/a19aca196dbb75b51b83fe7d06b0b7fce0f894b2_full.jpg",
1793 "steam_id": "76561199069631083",
1794 "sp_score": 65,
1795 "mp_score": 48,
1796 "overall_score": 113,
1797 "sp_rank": 1,
1798 "mp_rank": 7,
1799 "overall_rank": 1
1800 },
1801 {
1802 "user_name": "Kitsune",
1803 "avatar_link": "https://avatars.steamstatic.com/20bd0d2ff33f74c95500c5d11d4b550aa04fe505_full.jpg",
1804 "steam_id": "76561198136477838",
1805 "sp_score": 136,
1806 "mp_score": 48,
1807 "overall_score": 184,
1808 "sp_rank": 56,
1809 "mp_rank": 7,
1810 "overall_rank": 37
1811 },
1812 {
1813 "user_name": "TeePeeWee",
1814 "avatar_link": "https://avatars.steamstatic.com/4392a52e384f22c9f77b539eb4b1aa2914880cdf_full.jpg",
1815 "steam_id": "76561199239427541",
1816 "sp_score": 90,
1817 "mp_score": 48,
1818 "overall_score": 138,
1819 "sp_rank": 15,
1820 "mp_rank": 7,
1821 "overall_rank": 10
1822 },
1823 {
1824 "user_name": "Tenacite the MAD Milshake",
1825 "avatar_link": "https://avatars.steamstatic.com/dc22cc282f8bd43f3efde936b7263130f09358b8_full.jpg",
1826 "steam_id": "76561198389681125",
1827 "sp_score": 152,
1828 "mp_score": 49,
1829 "overall_score": 201,
1830 "sp_rank": 69,
1831 "mp_rank": 8,
1832 "overall_rank": 45
1833 },
1834 {
1835 "user_name": "DM_",
1836 "avatar_link": "https://avatars.steamstatic.com/417410dd471a369af956619daa7579263045bbba_full.jpg",
1837 "steam_id": "76561198003598363",
1838 "sp_score": 57,
1839 "mp_score": 49,
1840 "overall_score": 0,
1841 "sp_rank": 0,
1842 "mp_rank": 8,
1843 "overall_rank": 0
1844 },
1845 {
1846 "user_name": "mOtYl",
1847 "avatar_link": "https://avatars.steamstatic.com/8065f6018757dc0ee927d2279ccf7e8ab7827109_full.jpg",
1848 "steam_id": "76561197994700458",
1849 "sp_score": 74,
1850 "mp_score": 49,
1851 "overall_score": 123,
1852 "sp_rank": 3,
1853 "mp_rank": 8,
1854 "overall_rank": 3
1855 },
1856 {
1857 "user_name": "marKappa",
1858 "avatar_link": "https://avatars.steamstatic.com/e558017b19d0bbed38beb40f96211dccbb18ef3d_full.jpg",
1859 "steam_id": "76561198073902504",
1860 "sp_score": 101,
1861 "mp_score": 49,
1862 "overall_score": 0,
1863 "sp_rank": 0,
1864 "mp_rank": 8,
1865 "overall_rank": 0
1866 },
1867 {
1868 "user_name": "Linus",
1869 "avatar_link": "https://avatars.steamstatic.com/cfaf6917f47ca6122396f46e485a79a090f29fa0_full.jpg",
1870 "steam_id": "76561198162078579",
1871 "sp_score": 92,
1872 "mp_score": 49,
1873 "overall_score": 141,
1874 "sp_rank": 17,
1875 "mp_rank": 8,
1876 "overall_rank": 12
1877 },
1878 {
1879 "user_name": "Robotwars1",
1880 "avatar_link": "https://avatars.steamstatic.com/ac4bc6cc73ef75f11690205b123685fd5e3a7823_full.jpg",
1881 "steam_id": "76561198129010912",
1882 "sp_score": 86,
1883 "mp_score": 49,
1884 "overall_score": 135,
1885 "sp_rank": 11,
1886 "mp_rank": 8,
1887 "overall_rank": 9
1888 },
1889 {
1890 "user_name": "(MGN)-ZGP-NIKITA",
1891 "avatar_link": "https://avatars.steamstatic.com/8a72e1ed5a29e56c24926ccb33879a544bc67b36_full.jpg",
1892 "steam_id": "76561198076017585",
1893 "sp_score": 91,
1894 "mp_score": 49,
1895 "overall_score": 140,
1896 "sp_rank": 16,
1897 "mp_rank": 8,
1898 "overall_rank": 11
1899 },
1900 {
1901 "user_name": "LittleRoi",
1902 "avatar_link": "https://avatars.steamstatic.com/c9180f93ac892fa7d078f5946239d049e987e3b6_full.jpg",
1903 "steam_id": "76561198112477703",
1904 "sp_score": 85,
1905 "mp_score": 50,
1906 "overall_score": 135,
1907 "sp_rank": 10,
1908 "mp_rank": 9,
1909 "overall_rank": 9
1910 },
1911 {
1912 "user_name": "skz",
1913 "avatar_link": "https://avatars.steamstatic.com/7438cfa261a33ecdf2903e1a61b96173b6c5744a_full.jpg",
1914 "steam_id": "76561198323090545",
1915 "sp_score": 93,
1916 "mp_score": 50,
1917 "overall_score": 0,
1918 "sp_rank": 0,
1919 "mp_rank": 9,
1920 "overall_rank": 0
1921 },
1922 {
1923 "user_name": "KiloOnline",
1924 "avatar_link": "https://avatars.steamstatic.com/4ff11c7fe266f71b02c078e8dcc1374c3413b6f4_full.jpg",
1925 "steam_id": "76561198411125245",
1926 "sp_score": 170,
1927 "mp_score": 50,
1928 "overall_score": 0,
1929 "sp_rank": 0,
1930 "mp_rank": 9,
1931 "overall_rank": 0
1932 },
1933 {
1934 "user_name": "PerOculos",
1935 "avatar_link": "https://avatars.steamstatic.com/7b00906ac356806bc7bdb3815ea7c1c5b13b65a8_full.jpg",
1936 "steam_id": "76561198003223063",
1937 "sp_score": 84,
1938 "mp_score": 50,
1939 "overall_score": 134,
1940 "sp_rank": 9,
1941 "mp_rank": 9,
1942 "overall_rank": 8
1943 },
1944 {
1945 "user_name": "Suola",
1946 "avatar_link": "https://avatars.steamstatic.com/f86dcc2d065a87a603427bb382d26e96c1d61060_full.jpg",
1947 "steam_id": "76561198917972968",
1948 "sp_score": 98,
1949 "mp_score": 50,
1950 "overall_score": 148,
1951 "sp_rank": 22,
1952 "mp_rank": 9,
1953 "overall_rank": 16
1954 },
1955 {
1956 "user_name": "bob26798",
1957 "avatar_link": "https://avatars.steamstatic.com/cb940cd751f980d8d1374a66118a43f19985a1fa_full.jpg",
1958 "steam_id": "76561198278905764",
1959 "sp_score": 107,
1960 "mp_score": 51,
1961 "overall_score": 158,
1962 "sp_rank": 30,
1963 "mp_rank": 10,
1964 "overall_rank": 21
1965 },
1966 {
1967 "user_name": "Façade",
1968 "avatar_link": "https://avatars.steamstatic.com/f22455f600a546fd6200325e64cae2673ea89087_full.jpg",
1969 "steam_id": "76561198355852293",
1970 "sp_score": 88,
1971 "mp_score": 51,
1972 "overall_score": 0,
1973 "sp_rank": 0,
1974 "mp_rank": 10,
1975 "overall_rank": 0
1976 },
1977 {
1978 "user_name": "Lowengeist",
1979 "avatar_link": "https://avatars.steamstatic.com/4f9a9168c48434a27dfe32d5831ce9fdcfb3ed96_full.jpg",
1980 "steam_id": "76561198122276362",
1981 "sp_score": 110,
1982 "mp_score": 51,
1983 "overall_score": 161,
1984 "sp_rank": 33,
1985 "mp_rank": 10,
1986 "overall_rank": 24
1987 },
1988 {
1989 "user_name": "Evandar",
1990 "avatar_link": "https://avatars.steamstatic.com/22cf9a2e336958503ef008e6e0e4fb4b30106e67_full.jpg",
1991 "steam_id": "76561198204823324",
1992 "sp_score": 31,
1993 "mp_score": 51,
1994 "overall_score": 0,
1995 "sp_rank": 0,
1996 "mp_rank": 10,
1997 "overall_rank": 0
1998 },
1999 {
2000 "user_name": "((♡Murka♡))",
2001 "avatar_link": "https://avatars.steamstatic.com/8bb6a4d7223c09446bc0abb6570e5912d7f8b275_full.jpg",
2002 "steam_id": "76561198289477061",
2003 "sp_score": 71,
2004 "mp_score": 51,
2005 "overall_score": 0,
2006 "sp_rank": 0,
2007 "mp_rank": 10,
2008 "overall_rank": 0
2009 },
2010 {
2011 "user_name": "Fridge",
2012 "avatar_link": "https://avatars.steamstatic.com/ba9584900b25936d72bd8b7fb028eea0b0d0fa56_full.jpg",
2013 "steam_id": "76561198367132611",
2014 "sp_score": 115,
2015 "mp_score": 51,
2016 "overall_score": 166,
2017 "sp_rank": 38,
2018 "mp_rank": 10,
2019 "overall_rank": 26
2020 },
2021 {
2022 "user_name": "Extension",
2023 "avatar_link": "https://avatars.steamstatic.com/a647685b273a238928180573feb8135944d2795c_full.jpg",
2024 "steam_id": "76561198174735211",
2025 "sp_score": 108,
2026 "mp_score": 51,
2027 "overall_score": 159,
2028 "sp_rank": 31,
2029 "mp_rank": 10,
2030 "overall_rank": 22
2031 },
2032 {
2033 "user_name": "fin",
2034 "avatar_link": "https://avatars.steamstatic.com/c2e1bc09d5ab84143baa3c42d7131406beecdeba_full.jpg",
2035 "steam_id": "76561198150619409",
2036 "sp_score": 135,
2037 "mp_score": 51,
2038 "overall_score": 0,
2039 "sp_rank": 0,
2040 "mp_rank": 10,
2041 "overall_rank": 0
2042 },
2043 {
2044 "user_name": "็",
2045 "avatar_link": "https://avatars.steamstatic.com/66c216c1af7785f91dc1ac8b750a00295d7789aa_full.jpg",
2046 "steam_id": "76561198077911518",
2047 "sp_score": 13,
2048 "mp_score": 51,
2049 "overall_score": 0,
2050 "sp_rank": 0,
2051 "mp_rank": 10,
2052 "overall_rank": 0
2053 },
2054 {
2055 "user_name": "Confusion_18",
2056 "avatar_link": "https://avatars.steamstatic.com/360236e555049f204b12d3a8685a3b9b9764ebfe_full.jpg",
2057 "steam_id": "76561198386577258",
2058 "sp_score": 91,
2059 "mp_score": 51,
2060 "overall_score": 142,
2061 "sp_rank": 16,
2062 "mp_rank": 10,
2063 "overall_rank": 13
2064 },
2065 {
2066 "user_name": "Anigol",
2067 "avatar_link": "https://avatars.steamstatic.com/9ab1bec88da45ea89e5cd6a544e1d52bbbfcbd22_full.jpg",
2068 "steam_id": "76561198032217509",
2069 "sp_score": 57,
2070 "mp_score": 52,
2071 "overall_score": 0,
2072 "sp_rank": 0,
2073 "mp_rank": 11,
2074 "overall_rank": 0
2075 },
2076 {
2077 "user_name": "sear",
2078 "avatar_link": "https://avatars.steamstatic.com/a2759af9b274633d86b28dfd1b9e70675f41d44e_full.jpg",
2079 "steam_id": "76561198202719682",
2080 "sp_score": 98,
2081 "mp_score": 52,
2082 "overall_score": 0,
2083 "sp_rank": 0,
2084 "mp_rank": 11,
2085 "overall_rank": 0
2086 },
2087 {
2088 "user_name": "Myhr",
2089 "avatar_link": "https://avatars.steamstatic.com/deec440da6c13c8fa72f003d8396c15d6238c89e_full.jpg",
2090 "steam_id": "76561198054566481",
2091 "sp_score": 141,
2092 "mp_score": 52,
2093 "overall_score": 193,
2094 "sp_rank": 61,
2095 "mp_rank": 11,
2096 "overall_rank": 42
2097 },
2098 {
2099 "user_name": "Krzyhau",
2100 "avatar_link": "https://avatars.steamstatic.com/f29de7f41db29526848b52c8942f727b7c70b0db_full.jpg",
2101 "steam_id": "76561198096446735",
2102 "sp_score": 89,
2103 "mp_score": 52,
2104 "overall_score": 141,
2105 "sp_rank": 14,
2106 "mp_rank": 11,
2107 "overall_rank": 12
2108 },
2109 {
2110 "user_name": "Daddy Sparky420",
2111 "avatar_link": "https://avatars.steamstatic.com/14bd5c9bee517058bed74638465e5f68f8ce1d68_full.jpg",
2112 "steam_id": "76561198044110926",
2113 "sp_score": 108,
2114 "mp_score": 52,
2115 "overall_score": 160,
2116 "sp_rank": 31,
2117 "mp_rank": 11,
2118 "overall_rank": 23
2119 },
2120 {
2121 "user_name": "TheLucky",
2122 "avatar_link": "https://avatars.steamstatic.com/0e96fd1da4c91017a7c1de980d6361b139e6831d_full.jpg",
2123 "steam_id": "76561199116383198",
2124 "sp_score": 0,
2125 "mp_score": 53,
2126 "overall_score": 0,
2127 "sp_rank": 0,
2128 "mp_rank": 12,
2129 "overall_rank": 0
2130 },
2131 {
2132 "user_name": "Morality",
2133 "avatar_link": "https://avatars.steamstatic.com/2ea3e5885aa789acfc3640788905a414c408edc9_full.jpg",
2134 "steam_id": "76561198799058701",
2135 "sp_score": 115,
2136 "mp_score": 53,
2137 "overall_score": 168,
2138 "sp_rank": 38,
2139 "mp_rank": 12,
2140 "overall_rank": 27
2141 },
2142 {
2143 "user_name": "unity",
2144 "avatar_link": "https://avatars.steamstatic.com/1fcc7701ff71dce31965e10408d79aeb79bdf051_full.jpg",
2145 "steam_id": "76561198081168311",
2146 "sp_score": 96,
2147 "mp_score": 53,
2148 "overall_score": 149,
2149 "sp_rank": 20,
2150 "mp_rank": 12,
2151 "overall_rank": 17
2152 },
2153 {
2154 "user_name": "savvydruid",
2155 "avatar_link": "https://avatars.steamstatic.com/687d290c9238b42a790216892cc21f718741bd83_full.jpg",
2156 "steam_id": "76561199013726692",
2157 "sp_score": 157,
2158 "mp_score": 53,
2159 "overall_score": 210,
2160 "sp_rank": 74,
2161 "mp_rank": 12,
2162 "overall_rank": 47
2163 },
2164 {
2165 "user_name": "fullheart2",
2166 "avatar_link": "https://avatars.steamstatic.com/1daea993c3be4435d49bc50f7b011d639a08f3c9_full.jpg",
2167 "steam_id": "76561197997838862",
2168 "sp_score": 108,
2169 "mp_score": 53,
2170 "overall_score": 161,
2171 "sp_rank": 31,
2172 "mp_rank": 12,
2173 "overall_rank": 24
2174 },
2175 {
2176 "user_name": "timurkazz",
2177 "avatar_link": "https://avatars.steamstatic.com/13f6adfa0189055299b1ed69418eec8dd3b5d9eb_full.jpg",
2178 "steam_id": "76561199106449775",
2179 "sp_score": 115,
2180 "mp_score": 53,
2181 "overall_score": 168,
2182 "sp_rank": 38,
2183 "mp_rank": 12,
2184 "overall_rank": 27
2185 },
2186 {
2187 "user_name": "Travence",
2188 "avatar_link": "https://avatars.steamstatic.com/30247f75ad7b7e688654a28daa6ad4b035646281_full.jpg",
2189 "steam_id": "76561198071063948",
2190 "sp_score": 15,
2191 "mp_score": 53,
2192 "overall_score": 0,
2193 "sp_rank": 0,
2194 "mp_rank": 12,
2195 "overall_rank": 0
2196 },
2197 {
2198 "user_name": "SparKy",
2199 "avatar_link": "https://avatars.steamstatic.com/9f65ea65a977d44044bcf2130590793604435461_full.jpg",
2200 "steam_id": "76561198145522438",
2201 "sp_score": 96,
2202 "mp_score": 53,
2203 "overall_score": 0,
2204 "sp_rank": 0,
2205 "mp_rank": 12,
2206 "overall_rank": 0
2207 },
2208 {
2209 "user_name": "RubiksImplosion",
2210 "avatar_link": "https://avatars.steamstatic.com/2ff1c8d37a2b6b2f370e9a7f204c1c2f64278e51_full.jpg",
2211 "steam_id": "76561198140834873",
2212 "sp_score": 121,
2213 "mp_score": 53,
2214 "overall_score": 0,
2215 "sp_rank": 0,
2216 "mp_rank": 12,
2217 "overall_rank": 0
2218 },
2219 {
2220 "user_name": "S h i r o \u003c3",
2221 "avatar_link": "https://avatars.steamstatic.com/f1df5185c33b7b75206e6e7da8d45bb6ae298c2c_full.jpg",
2222 "steam_id": "76561198134829983",
2223 "sp_score": 19,
2224 "mp_score": 54,
2225 "overall_score": 0,
2226 "sp_rank": 0,
2227 "mp_rank": 13,
2228 "overall_rank": 0
2229 },
2230 {
2231 "user_name": "do be chillin",
2232 "avatar_link": "https://avatars.steamstatic.com/c81b318ef886d99a73b6f94ad90b7701ea488b44_full.jpg",
2233 "steam_id": "76561197999637837",
2234 "sp_score": 10,
2235 "mp_score": 54,
2236 "overall_score": 0,
2237 "sp_rank": 0,
2238 "mp_rank": 13,
2239 "overall_rank": 0
2240 },
2241 {
2242 "user_name": "⭕⃤-Koolusel",
2243 "avatar_link": "https://avatars.steamstatic.com/910a151974aa1880b218e0baeafb0cca8597a554_full.jpg",
2244 "steam_id": "76561198054179479",
2245 "sp_score": 110,
2246 "mp_score": 54,
2247 "overall_score": 0,
2248 "sp_rank": 0,
2249 "mp_rank": 13,
2250 "overall_rank": 0
2251 },
2252 {
2253 "user_name": "CeyHun",
2254 "avatar_link": "https://avatars.steamstatic.com/c810b0d7bc7755cf71da650329fced17b5afc1ed_full.jpg",
2255 "steam_id": "76561198809051111",
2256 "sp_score": 127,
2257 "mp_score": 54,
2258 "overall_score": 0,
2259 "sp_rank": 0,
2260 "mp_rank": 13,
2261 "overall_rank": 0
2262 },
2263 {
2264 "user_name": "nintendude",
2265 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
2266 "steam_id": "76561198307085542",
2267 "sp_score": 118,
2268 "mp_score": 54,
2269 "overall_score": 172,
2270 "sp_rank": 40,
2271 "mp_rank": 13,
2272 "overall_rank": 30
2273 },
2274 {
2275 "user_name": "Syho",
2276 "avatar_link": "https://avatars.steamstatic.com/b682ace9a42eedb29ef840079f630da7520a9d35_full.jpg",
2277 "steam_id": "76561198043570840",
2278 "sp_score": 0,
2279 "mp_score": 54,
2280 "overall_score": 0,
2281 "sp_rank": 0,
2282 "mp_rank": 13,
2283 "overall_rank": 0
2284 },
2285 {
2286 "user_name": "Number1S0n",
2287 "avatar_link": "https://avatars.steamstatic.com/3de2434127aaa6f8b507f4ba37fda2de66b28d02_full.jpg",
2288 "steam_id": "76561198261284319",
2289 "sp_score": 81,
2290 "mp_score": 55,
2291 "overall_score": 0,
2292 "sp_rank": 0,
2293 "mp_rank": 14,
2294 "overall_rank": 0
2295 },
2296 {
2297 "user_name": "grapefruit",
2298 "avatar_link": "https://avatars.steamstatic.com/ae7603dbeb28ea6b1870547f8dc5017ab5240fb9_full.jpg",
2299 "steam_id": "76561198084554697",
2300 "sp_score": 155,
2301 "mp_score": 55,
2302 "overall_score": 0,
2303 "sp_rank": 0,
2304 "mp_rank": 14,
2305 "overall_rank": 0
2306 },
2307 {
2308 "user_name": "Fyrestorm",
2309 "avatar_link": "https://avatars.steamstatic.com/c0c82fa70c986348caaaea71f3ccac1b13c0c4eb_full.jpg",
2310 "steam_id": "76561198035761863",
2311 "sp_score": 142,
2312 "mp_score": 55,
2313 "overall_score": 197,
2314 "sp_rank": 62,
2315 "mp_rank": 14,
2316 "overall_rank": 43
2317 },
2318 {
2319 "user_name": "マジックサラダ",
2320 "avatar_link": "https://avatars.steamstatic.com/8772186a3ab48712b6eb955a46d269b52ebda706_full.jpg",
2321 "steam_id": "76561198092289827",
2322 "sp_score": 93,
2323 "mp_score": 55,
2324 "overall_score": 148,
2325 "sp_rank": 18,
2326 "mp_rank": 14,
2327 "overall_rank": 16
2328 },
2329 {
2330 "user_name": "h@iku",
2331 "avatar_link": "https://avatars.steamstatic.com/bfb0f0be647a28135ba306cd2e40c6ece3ca11b2_full.jpg",
2332 "steam_id": "76561198343098423",
2333 "sp_score": 123,
2334 "mp_score": 55,
2335 "overall_score": 178,
2336 "sp_rank": 43,
2337 "mp_rank": 14,
2338 "overall_rank": 34
2339 },
2340 {
2341 "user_name": "Shiro",
2342 "avatar_link": "https://avatars.steamstatic.com/7160e03d7c638627813e5fb993bf921c828b02c2_full.jpg",
2343 "steam_id": "76561198118924124",
2344 "sp_score": 119,
2345 "mp_score": 55,
2346 "overall_score": 174,
2347 "sp_rank": 41,
2348 "mp_rank": 14,
2349 "overall_rank": 31
2350 },
2351 {
2352 "user_name": "Zypeh",
2353 "avatar_link": "https://avatars.steamstatic.com/bfd2b759e7e6300fc709857b9e6db802084544d1_full.jpg",
2354 "steam_id": "76561198039230536",
2355 "sp_score": 106,
2356 "mp_score": 55,
2357 "overall_score": 161,
2358 "sp_rank": 29,
2359 "mp_rank": 14,
2360 "overall_rank": 24
2361 },
2362 {
2363 "user_name": "Kiby",
2364 "avatar_link": "https://avatars.steamstatic.com/d6c1a2ce06f27072faea47f5b66e619966e0e74a_full.jpg",
2365 "steam_id": "76561198244043338",
2366 "sp_score": 160,
2367 "mp_score": 55,
2368 "overall_score": 0,
2369 "sp_rank": 0,
2370 "mp_rank": 14,
2371 "overall_rank": 0
2372 },
2373 {
2374 "user_name": "76561199087561281",
2375 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
2376 "steam_id": "76561199087561281",
2377 "sp_score": 0,
2378 "mp_score": 55,
2379 "overall_score": 0,
2380 "sp_rank": 0,
2381 "mp_rank": 14,
2382 "overall_rank": 0
2383 },
2384 {
2385 "user_name": "Hyper",
2386 "avatar_link": "https://avatars.steamstatic.com/13a8255802e0794e1fc8c97994559e08761c9100_full.jpg",
2387 "steam_id": "76561198072650129",
2388 "sp_score": 159,
2389 "mp_score": 55,
2390 "overall_score": 0,
2391 "sp_rank": 0,
2392 "mp_rank": 14,
2393 "overall_rank": 0
2394 },
2395 {
2396 "user_name": "Elixterr",
2397 "avatar_link": "https://avatars.steamstatic.com/655c5f07b60dbe45071fe9eb3f442762009a4022_full.jpg",
2398 "steam_id": "76561198025166178",
2399 "sp_score": 121,
2400 "mp_score": 56,
2401 "overall_score": 0,
2402 "sp_rank": 0,
2403 "mp_rank": 15,
2404 "overall_rank": 0
2405 },
2406 {
2407 "user_name": "Snow",
2408 "avatar_link": "https://avatars.steamstatic.com/64b513f2c1f8a490670aa3d004d71b95207035b8_full.jpg",
2409 "steam_id": "76561198842803939",
2410 "sp_score": 121,
2411 "mp_score": 56,
2412 "overall_score": 177,
2413 "sp_rank": 42,
2414 "mp_rank": 15,
2415 "overall_rank": 33
2416 },
2417 {
2418 "user_name": "Soulfur",
2419 "avatar_link": "https://avatars.steamstatic.com/af59571446fe62756d619b9e42a82c432390ccf0_full.jpg",
2420 "steam_id": "76561198181126266",
2421 "sp_score": 135,
2422 "mp_score": 56,
2423 "overall_score": 191,
2424 "sp_rank": 55,
2425 "mp_rank": 15,
2426 "overall_rank": 41
2427 },
2428 {
2429 "user_name": "Blenderiste09",
2430 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
2431 "steam_id": "76561198251755710",
2432 "sp_score": 145,
2433 "mp_score": 56,
2434 "overall_score": 201,
2435 "sp_rank": 65,
2436 "mp_rank": 15,
2437 "overall_rank": 45
2438 },
2439 {
2440 "user_name": "laredeshot",
2441 "avatar_link": "https://avatars.steamstatic.com/8ffb58e0cddad5293c48250deb458f428b9f6736_full.jpg",
2442 "steam_id": "76561198261656551",
2443 "sp_score": 149,
2444 "mp_score": 56,
2445 "overall_score": 205,
2446 "sp_rank": 67,
2447 "mp_rank": 15,
2448 "overall_rank": 46
2449 },
2450 {
2451 "user_name": "Auraxed",
2452 "avatar_link": "https://avatars.steamstatic.com/e1be233d73cc82d0c1a3dcfea0d321d3a9c5d432_full.jpg",
2453 "steam_id": "76561197995148325",
2454 "sp_score": 171,
2455 "mp_score": 57,
2456 "overall_score": 0,
2457 "sp_rank": 0,
2458 "mp_rank": 16,
2459 "overall_rank": 0
2460 },
2461 {
2462 "user_name": "NeKz",
2463 "avatar_link": "https://avatars.steamstatic.com/9a86e6554aee395b3ac37d96a808335363eb79ff_full.jpg",
2464 "steam_id": "76561198049848090",
2465 "sp_score": 107,
2466 "mp_score": 57,
2467 "overall_score": 164,
2468 "sp_rank": 30,
2469 "mp_rank": 16,
2470 "overall_rank": 25
2471 },
2472 {
2473 "user_name": "AMJ",
2474 "avatar_link": "https://avatars.steamstatic.com/43480cfa66f1b35c2098016221a4dc19ed4fab55_full.jpg",
2475 "steam_id": "76561198067936604",
2476 "sp_score": 121,
2477 "mp_score": 57,
2478 "overall_score": 178,
2479 "sp_rank": 42,
2480 "mp_rank": 16,
2481 "overall_rank": 34
2482 },
2483 {
2484 "user_name": "Turmoil",
2485 "avatar_link": "https://avatars.steamstatic.com/ceeb79bfd441b1928af34195dfde660b44f002dd_full.jpg",
2486 "steam_id": "76561197997770103",
2487 "sp_score": 142,
2488 "mp_score": 57,
2489 "overall_score": 199,
2490 "sp_rank": 62,
2491 "mp_rank": 16,
2492 "overall_rank": 44
2493 },
2494 {
2495 "user_name": "wol",
2496 "avatar_link": "https://avatars.steamstatic.com/689a4b1be66db3f28a1567c7b1bb7e8e2d1e1d90_full.jpg",
2497 "steam_id": "76561199007976762",
2498 "sp_score": 177,
2499 "mp_score": 57,
2500 "overall_score": 234,
2501 "sp_rank": 84,
2502 "mp_rank": 16,
2503 "overall_rank": 54
2504 },
2505 {
2506 "user_name": "SrRageALot",
2507 "avatar_link": "https://avatars.steamstatic.com/db9c6b6761d63c640456043d864f98f58f62d750_full.jpg",
2508 "steam_id": "76561199156418931",
2509 "sp_score": 89,
2510 "mp_score": 57,
2511 "overall_score": 146,
2512 "sp_rank": 14,
2513 "mp_rank": 16,
2514 "overall_rank": 14
2515 },
2516 {
2517 "user_name": "Dreadnox",
2518 "avatar_link": "https://avatars.steamstatic.com/5a01939cd01c969e34417a75116c1167ed74cda5_full.jpg",
2519 "steam_id": "76561198346371604",
2520 "sp_score": 151,
2521 "mp_score": 57,
2522 "overall_score": 0,
2523 "sp_rank": 0,
2524 "mp_rank": 16,
2525 "overall_rank": 0
2526 },
2527 {
2528 "user_name": "Jess3n",
2529 "avatar_link": "https://avatars.steamstatic.com/1ee47a4ad1a50a4307cde6a9c543b3207942596c_full.jpg",
2530 "steam_id": "76561198870020820",
2531 "sp_score": 112,
2532 "mp_score": 58,
2533 "overall_score": 170,
2534 "sp_rank": 35,
2535 "mp_rank": 17,
2536 "overall_rank": 28
2537 },
2538 {
2539 "user_name": "Chevalix",
2540 "avatar_link": "https://avatars.steamstatic.com/db8a0073f499823d0fb4ba89ee8716971a321a4e_full.jpg",
2541 "steam_id": "76561198302681368",
2542 "sp_score": 121,
2543 "mp_score": 58,
2544 "overall_score": 179,
2545 "sp_rank": 42,
2546 "mp_rank": 17,
2547 "overall_rank": 35
2548 },
2549 {
2550 "user_name": "Jarool",
2551 "avatar_link": "https://avatars.steamstatic.com/61bb4ee9a8dd6cef5427f2170bb75d3162f3c8e8_full.jpg",
2552 "steam_id": "76561198021055079",
2553 "sp_score": 107,
2554 "mp_score": 59,
2555 "overall_score": 166,
2556 "sp_rank": 30,
2557 "mp_rank": 18,
2558 "overall_rank": 26
2559 },
2560 {
2561 "user_name": "Lathil",
2562 "avatar_link": "https://avatars.steamstatic.com/6636331f0f7d69a2ef6557a124ae4a3389466047_full.jpg",
2563 "steam_id": "76561198404861950",
2564 "sp_score": 165,
2565 "mp_score": 59,
2566 "overall_score": 224,
2567 "sp_rank": 79,
2568 "mp_rank": 18,
2569 "overall_rank": 50
2570 },
2571 {
2572 "user_name": "c",
2573 "avatar_link": "https://avatars.steamstatic.com/e1be34a0f74d128594230f4518b20c3070e33f9f_full.jpg",
2574 "steam_id": "76561199002783681",
2575 "sp_score": 22,
2576 "mp_score": 59,
2577 "overall_score": 0,
2578 "sp_rank": 0,
2579 "mp_rank": 18,
2580 "overall_rank": 0
2581 },
2582 {
2583 "user_name": "cubone",
2584 "avatar_link": "https://avatars.steamstatic.com/e285359230318e5cfb27ed688903c5350cd21075_full.jpg",
2585 "steam_id": "76561198096862334",
2586 "sp_score": 93,
2587 "mp_score": 59,
2588 "overall_score": 152,
2589 "sp_rank": 18,
2590 "mp_rank": 18,
2591 "overall_rank": 19
2592 },
2593 {
2594 "user_name": "shred",
2595 "avatar_link": "https://avatars.steamstatic.com/0216ce300d00ec193414773679db7dcd77d1cd29_full.jpg",
2596 "steam_id": "76561198025486280",
2597 "sp_score": 88,
2598 "mp_score": 59,
2599 "overall_score": 147,
2600 "sp_rank": 13,
2601 "mp_rank": 18,
2602 "overall_rank": 15
2603 },
2604 {
2605 "user_name": "plaasdfds",
2606 "avatar_link": "https://avatars.steamstatic.com/a8cce5c848ed9f27b7252b2490a43c3880ac35b4_full.jpg",
2607 "steam_id": "76561198970030910",
2608 "sp_score": 54,
2609 "mp_score": 59,
2610 "overall_score": 0,
2611 "sp_rank": 0,
2612 "mp_rank": 18,
2613 "overall_rank": 0
2614 },
2615 {
2616 "user_name": "/7e4eHbKa",
2617 "avatar_link": "https://avatars.steamstatic.com/4925eeeb2c413b3937d99a5a5c2f112668b1dcbd_full.jpg",
2618 "steam_id": "76561198148745518",
2619 "sp_score": 0,
2620 "mp_score": 59,
2621 "overall_score": 0,
2622 "sp_rank": 0,
2623 "mp_rank": 18,
2624 "overall_rank": 0
2625 },
2626 {
2627 "user_name": "Nana",
2628 "avatar_link": "https://avatars.steamstatic.com/82f49763c2329f3fdc32c1319b8b0f884b1a8c27_full.jpg",
2629 "steam_id": "76561198356541694",
2630 "sp_score": 39,
2631 "mp_score": 60,
2632 "overall_score": 0,
2633 "sp_rank": 0,
2634 "mp_rank": 19,
2635 "overall_rank": 0
2636 },
2637 {
2638 "user_name": "Leve",
2639 "avatar_link": "https://avatars.steamstatic.com/7a56621890546d1a54d4b583198b4d30411950b2_full.jpg",
2640 "steam_id": "76561198902321340",
2641 "sp_score": 111,
2642 "mp_score": 60,
2643 "overall_score": 171,
2644 "sp_rank": 34,
2645 "mp_rank": 19,
2646 "overall_rank": 29
2647 },
2648 {
2649 "user_name": "Extension",
2650 "avatar_link": "https://avatars.steamstatic.com/dbaf3958fffebf266ce5c04316da744987e9b1fb_full.jpg",
2651 "steam_id": "76561199221334063",
2652 "sp_score": 99,
2653 "mp_score": 61,
2654 "overall_score": 160,
2655 "sp_rank": 23,
2656 "mp_rank": 20,
2657 "overall_rank": 23
2658 },
2659 {
2660 "user_name": "Herneerius",
2661 "avatar_link": "https://avatars.steamstatic.com/4879fa1c72770b2c0eaef341dc6546db13897bb5_full.jpg",
2662 "steam_id": "76561198084978888",
2663 "sp_score": 98,
2664 "mp_score": 61,
2665 "overall_score": 159,
2666 "sp_rank": 22,
2667 "mp_rank": 20,
2668 "overall_rank": 22
2669 },
2670 {
2671 "user_name": "Nate",
2672 "avatar_link": "https://avatars.steamstatic.com/b92b7b2b2828e19865b8a86c40d7eed999cae008_full.jpg",
2673 "steam_id": "76561198172465698",
2674 "sp_score": 146,
2675 "mp_score": 62,
2676 "overall_score": 0,
2677 "sp_rank": 0,
2678 "mp_rank": 21,
2679 "overall_rank": 0
2680 },
2681 {
2682 "user_name": "stip",
2683 "avatar_link": "https://avatars.steamstatic.com/19be8fd7d791a14920566ce35cc2798ecda8a9e4_full.jpg",
2684 "steam_id": "76561198238515424",
2685 "sp_score": 113,
2686 "mp_score": 63,
2687 "overall_score": 176,
2688 "sp_rank": 36,
2689 "mp_rank": 22,
2690 "overall_rank": 32
2691 },
2692 {
2693 "user_name": "なぜ",
2694 "avatar_link": "https://avatars.steamstatic.com/910b3cd2736125678ec6c2744807d0eed052282a_full.jpg",
2695 "steam_id": "76561198220025727",
2696 "sp_score": 176,
2697 "mp_score": 63,
2698 "overall_score": 0,
2699 "sp_rank": 0,
2700 "mp_rank": 22,
2701 "overall_rank": 0
2702 },
2703 {
2704 "user_name": "korA",
2705 "avatar_link": "https://avatars.steamstatic.com/f6b4b06701dac46a964c320bef20485d468ae35d_full.jpg",
2706 "steam_id": "76561198073626473",
2707 "sp_score": 82,
2708 "mp_score": 63,
2709 "overall_score": 0,
2710 "sp_rank": 0,
2711 "mp_rank": 22,
2712 "overall_rank": 0
2713 },
2714 {
2715 "user_name": "\u003eLIX",
2716 "avatar_link": "https://avatars.steamstatic.com/fde1a844f9705846e470cb24fc8bd37261b52267_full.jpg",
2717 "steam_id": "76561198134742054",
2718 "sp_score": 121,
2719 "mp_score": 63,
2720 "overall_score": 0,
2721 "sp_rank": 0,
2722 "mp_rank": 22,
2723 "overall_rank": 0
2724 },
2725 {
2726 "user_name": "Yugge",
2727 "avatar_link": "https://avatars.steamstatic.com/dc7c081330432a22b2d44cca2c02285c3ad04813_full.jpg",
2728 "steam_id": "76561198405615224",
2729 "sp_score": 117,
2730 "mp_score": 63,
2731 "overall_score": 180,
2732 "sp_rank": 39,
2733 "mp_rank": 22,
2734 "overall_rank": 36
2735 },
2736 {
2737 "user_name": "Klooger",
2738 "avatar_link": "https://avatars.steamstatic.com/5e3a2e97e84c3a6c12cf63ed5c5d22edee6ecec5_full.jpg",
2739 "steam_id": "76561198015678746",
2740 "sp_score": 160,
2741 "mp_score": 64,
2742 "overall_score": 0,
2743 "sp_rank": 0,
2744 "mp_rank": 23,
2745 "overall_rank": 0
2746 },
2747 {
2748 "user_name": "ุ",
2749 "avatar_link": "https://avatars.steamstatic.com/b698f81978cd408b5e210f5b5c09d308ae75165b_full.jpg",
2750 "steam_id": "76561198200883819",
2751 "sp_score": 121,
2752 "mp_score": 64,
2753 "overall_score": 185,
2754 "sp_rank": 42,
2755 "mp_rank": 23,
2756 "overall_rank": 38
2757 },
2758 {
2759 "user_name": "Bexc",
2760 "avatar_link": "https://avatars.steamstatic.com/67244cfd34ce0dfe36db3e1b8c1b81fe685bfc68_full.jpg",
2761 "steam_id": "76561198295368421",
2762 "sp_score": 129,
2763 "mp_score": 65,
2764 "overall_score": 0,
2765 "sp_rank": 0,
2766 "mp_rank": 24,
2767 "overall_rank": 0
2768 },
2769 {
2770 "user_name": "100kitaizzev",
2771 "avatar_link": "https://avatars.steamstatic.com/93c7cb31e2b51e636e308788c7264b70e9756c9d_full.jpg",
2772 "steam_id": "76561198006939388",
2773 "sp_score": 123,
2774 "mp_score": 65,
2775 "overall_score": 188,
2776 "sp_rank": 43,
2777 "mp_rank": 24,
2778 "overall_rank": 39
2779 },
2780 {
2781 "user_name": "ADGOD",
2782 "avatar_link": "https://avatars.steamstatic.com/a2729f28a4579f519645a10fa3a0e93e66bfa9ed_full.jpg",
2783 "steam_id": "76561198054640750",
2784 "sp_score": 168,
2785 "mp_score": 65,
2786 "overall_score": 0,
2787 "sp_rank": 0,
2788 "mp_rank": 24,
2789 "overall_rank": 0
2790 },
2791 {
2792 "user_name": "Mr_ParK3r2",
2793 "avatar_link": "https://avatars.steamstatic.com/b00c1c9f1d241b6f4b15fc92541964f29d7bf686_full.jpg",
2794 "steam_id": "76561198032249973",
2795 "sp_score": 178,
2796 "mp_score": 66,
2797 "overall_score": 0,
2798 "sp_rank": 0,
2799 "mp_rank": 25,
2800 "overall_rank": 0
2801 },
2802 {
2803 "user_name": "JustJack",
2804 "avatar_link": "https://avatars.steamstatic.com/a55267091e385756240f1a11b241981d784293a3_full.jpg",
2805 "steam_id": "76561198892691044",
2806 "sp_score": 172,
2807 "mp_score": 66,
2808 "overall_score": 0,
2809 "sp_rank": 0,
2810 "mp_rank": 25,
2811 "overall_rank": 0
2812 },
2813 {
2814 "user_name": "Burger40",
2815 "avatar_link": "https://avatars.steamstatic.com/00db94cf7b185c69936738b5a827c63d033c6479_full.jpg",
2816 "steam_id": "76561198083196477",
2817 "sp_score": 98,
2818 "mp_score": 66,
2819 "overall_score": 164,
2820 "sp_rank": 22,
2821 "mp_rank": 25,
2822 "overall_rank": 25
2823 },
2824 {
2825 "user_name": "MrCatMcFly",
2826 "avatar_link": "https://avatars.steamstatic.com/6f89591012f8f0f34cef1ecdb1c10793b0ea4bd1_full.jpg",
2827 "steam_id": "76561198168920589",
2828 "sp_score": 87,
2829 "mp_score": 66,
2830 "overall_score": 153,
2831 "sp_rank": 12,
2832 "mp_rank": 25,
2833 "overall_rank": 20
2834 },
2835 {
2836 "user_name": "DeSore",
2837 "avatar_link": "https://avatars.steamstatic.com/96d0fbbbfe33a04913c0078cdc7fdd67330f6597_full.jpg",
2838 "steam_id": "76561198833180630",
2839 "sp_score": 24,
2840 "mp_score": 67,
2841 "overall_score": 0,
2842 "sp_rank": 0,
2843 "mp_rank": 26,
2844 "overall_rank": 0
2845 },
2846 {
2847 "user_name": "Yarby",
2848 "avatar_link": "https://avatars.steamstatic.com/e4b15b25a74d72bb7d93dac7ddcae58984f99b86_full.jpg",
2849 "steam_id": "76561198043899549",
2850 "sp_score": 108,
2851 "mp_score": 68,
2852 "overall_score": 0,
2853 "sp_rank": 0,
2854 "mp_rank": 27,
2855 "overall_rank": 0
2856 },
2857 {
2858 "user_name": "Victim",
2859 "avatar_link": "https://avatars.steamstatic.com/b3d2986cfe9340530e69934dae7a316423f106d9_full.jpg",
2860 "steam_id": "76561198999589923",
2861 "sp_score": 0,
2862 "mp_score": 68,
2863 "overall_score": 0,
2864 "sp_rank": 0,
2865 "mp_rank": 27,
2866 "overall_rank": 0
2867 },
2868 {
2869 "user_name": "Pr0tal",
2870 "avatar_link": "https://avatars.steamstatic.com/ce72799aa2cf4b591df09b3afc715b2259963af7_full.jpg",
2871 "steam_id": "76561198292863694",
2872 "sp_score": 98,
2873 "mp_score": 68,
2874 "overall_score": 166,
2875 "sp_rank": 22,
2876 "mp_rank": 27,
2877 "overall_rank": 26
2878 },
2879 {
2880 "user_name": "X3kuba3X",
2881 "avatar_link": "https://avatars.steamstatic.com/244a92aebee196a0456bb89d287ffff19834eec0_full.jpg",
2882 "steam_id": "76561198134292189",
2883 "sp_score": 9,
2884 "mp_score": 69,
2885 "overall_score": 0,
2886 "sp_rank": 0,
2887 "mp_rank": 28,
2888 "overall_rank": 0
2889 },
2890 {
2891 "user_name": "Schwi",
2892 "avatar_link": "https://avatars.steamstatic.com/a5ab762db09205fc49a6fa8fd1d09daafc3ac6e4_full.jpg",
2893 "steam_id": "76561198384377251",
2894 "sp_score": 147,
2895 "mp_score": 69,
2896 "overall_score": 216,
2897 "sp_rank": 66,
2898 "mp_rank": 28,
2899 "overall_rank": 48
2900 },
2901 {
2902 "user_name": "DenisikPlayer",
2903 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
2904 "steam_id": "76561198337440587",
2905 "sp_score": 0,
2906 "mp_score": 70,
2907 "overall_score": 0,
2908 "sp_rank": 0,
2909 "mp_rank": 29,
2910 "overall_rank": 0
2911 },
2912 {
2913 "user_name": "rudko",
2914 "avatar_link": "https://avatars.steamstatic.com/b932115fe2e18117925e28499fa0cea637caf7bd_full.jpg",
2915 "steam_id": "76561198128079782",
2916 "sp_score": 143,
2917 "mp_score": 70,
2918 "overall_score": 0,
2919 "sp_rank": 0,
2920 "mp_rank": 29,
2921 "overall_rank": 0
2922 },
2923 {
2924 "user_name": "Imagine a cool name",
2925 "avatar_link": "https://avatars.steamstatic.com/ed6186b9c575f4df60c138785c9c004ad9bd4fae_full.jpg",
2926 "steam_id": "76561198869299905",
2927 "sp_score": 101,
2928 "mp_score": 71,
2929 "overall_score": 172,
2930 "sp_rank": 25,
2931 "mp_rank": 30,
2932 "overall_rank": 30
2933 },
2934 {
2935 "user_name": "ThatGoatWhoIsEpic",
2936 "avatar_link": "https://avatars.steamstatic.com/5049e37e3b511134a4a1b8359a8103348c09ff17_full.jpg",
2937 "steam_id": "76561198074525881",
2938 "sp_score": 117,
2939 "mp_score": 72,
2940 "overall_score": 189,
2941 "sp_rank": 39,
2942 "mp_rank": 31,
2943 "overall_rank": 40
2944 },
2945 {
2946 "user_name": "KurChuck",
2947 "avatar_link": "https://avatars.steamstatic.com/9506cc7cd5450190a64b45bab4eb2164054d9622_full.jpg",
2948 "steam_id": "76561198014816567",
2949 "sp_score": 41,
2950 "mp_score": 72,
2951 "overall_score": 0,
2952 "sp_rank": 0,
2953 "mp_rank": 31,
2954 "overall_rank": 0
2955 },
2956 {
2957 "user_name": "m a c k",
2958 "avatar_link": "https://avatars.steamstatic.com/1f8b38c318002f583a40874ff61cbf23621f1087_full.jpg",
2959 "steam_id": "76561198286321440",
2960 "sp_score": 13,
2961 "mp_score": 72,
2962 "overall_score": 0,
2963 "sp_rank": 0,
2964 "mp_rank": 31,
2965 "overall_rank": 0
2966 },
2967 {
2968 "user_name": "UrMomPlebLol",
2969 "avatar_link": "https://avatars.steamstatic.com/5b5b9357badc3d9e9ba53d52cf851a85df4a910c_full.jpg",
2970 "steam_id": "76561198371482646",
2971 "sp_score": 112,
2972 "mp_score": 73,
2973 "overall_score": 185,
2974 "sp_rank": 35,
2975 "mp_rank": 32,
2976 "overall_rank": 38
2977 },
2978 {
2979 "user_name": "follon",
2980 "avatar_link": "https://avatars.steamstatic.com/34f5aed96997089fcd0782d756c637a431666965_full.jpg",
2981 "steam_id": "76561198024055942",
2982 "sp_score": 118,
2983 "mp_score": 74,
2984 "overall_score": 0,
2985 "sp_rank": 0,
2986 "mp_rank": 33,
2987 "overall_rank": 0
2988 },
2989 {
2990 "user_name": "Saxton Hale",
2991 "avatar_link": "https://avatars.steamstatic.com/2f335962fbb8431ea3f5606fe3e1881dce47e63a_full.jpg",
2992 "steam_id": "76561197998253566",
2993 "sp_score": 155,
2994 "mp_score": 75,
2995 "overall_score": 230,
2996 "sp_rank": 72,
2997 "mp_rank": 34,
2998 "overall_rank": 52
2999 },
3000 {
3001 "user_name": "Amtyi",
3002 "avatar_link": "https://avatars.steamstatic.com/c320800aa0ee29bf778d5580afc191b5745be7f3_full.jpg",
3003 "steam_id": "76561198241550078",
3004 "sp_score": 74,
3005 "mp_score": 77,
3006 "overall_score": 0,
3007 "sp_rank": 0,
3008 "mp_rank": 35,
3009 "overall_rank": 0
3010 },
3011 {
3012 "user_name": "Throw",
3013 "avatar_link": "https://avatars.steamstatic.com/2c01a87d1b0789f7bdd1f3e693ef9987e49abe01_full.jpg",
3014 "steam_id": "76561198952505877",
3015 "sp_score": 115,
3016 "mp_score": 78,
3017 "overall_score": 193,
3018 "sp_rank": 38,
3019 "mp_rank": 36,
3020 "overall_rank": 42
3021 },
3022 {
3023 "user_name": "Clantis",
3024 "avatar_link": "https://avatars.steamstatic.com/5395f253dd2f4f26a76d8c12605d474ad6fb8dca_full.jpg",
3025 "steam_id": "76561198296352733",
3026 "sp_score": 142,
3027 "mp_score": 80,
3028 "overall_score": 0,
3029 "sp_rank": 0,
3030 "mp_rank": 37,
3031 "overall_rank": 0
3032 },
3033 {
3034 "user_name": "Xinera",
3035 "avatar_link": "https://avatars.steamstatic.com/9b8af4605d41bdd61ba3c27bd7ba8e8468a9a544_full.jpg",
3036 "steam_id": "76561198054297641",
3037 "sp_score": 140,
3038 "mp_score": 81,
3039 "overall_score": 0,
3040 "sp_rank": 0,
3041 "mp_rank": 38,
3042 "overall_rank": 0
3043 },
3044 {
3045 "user_name": "AaRCaT",
3046 "avatar_link": "https://avatars.steamstatic.com/ed6bd613d0ac4560683e59c03f824bf64972a5bd_full.jpg",
3047 "steam_id": "76561198158015341",
3048 "sp_score": 11,
3049 "mp_score": 82,
3050 "overall_score": 0,
3051 "sp_rank": 0,
3052 "mp_rank": 39,
3053 "overall_rank": 0
3054 },
3055 {
3056 "user_name": "Imanex",
3057 "avatar_link": "https://avatars.steamstatic.com/82d1ac52aeddb7f08eb0f85d4f7d96160af30bb9_full.jpg",
3058 "steam_id": "76561197974616889",
3059 "sp_score": 169,
3060 "mp_score": 82,
3061 "overall_score": 251,
3062 "sp_rank": 81,
3063 "mp_rank": 39,
3064 "overall_rank": 57
3065 },
3066 {
3067 "user_name": "Reau",
3068 "avatar_link": "https://avatars.steamstatic.com/6037ba76b789065685c47291eee8254b4934ad9c_full.jpg",
3069 "steam_id": "76561198272340873",
3070 "sp_score": 154,
3071 "mp_score": 82,
3072 "overall_score": 0,
3073 "sp_rank": 0,
3074 "mp_rank": 39,
3075 "overall_rank": 0
3076 },
3077 {
3078 "user_name": "1 Portal SWAG",
3079 "avatar_link": "https://avatars.steamstatic.com/8766c163ce9fd7a584c5347dab0a6a49766102e8_full.jpg",
3080 "steam_id": "76561198253811824",
3081 "sp_score": 137,
3082 "mp_score": 82,
3083 "overall_score": 219,
3084 "sp_rank": 57,
3085 "mp_rank": 39,
3086 "overall_rank": 49
3087 },
3088 {
3089 "user_name": "elle",
3090 "avatar_link": "https://avatars.steamstatic.com/2b6dd3fc173a2406a08cf4c02d3a67464e8fef44_full.jpg",
3091 "steam_id": "76561198821417994",
3092 "sp_score": 57,
3093 "mp_score": 85,
3094 "overall_score": 0,
3095 "sp_rank": 0,
3096 "mp_rank": 40,
3097 "overall_rank": 0
3098 },
3099 {
3100 "user_name": "Limehawk",
3101 "avatar_link": "https://avatars.steamstatic.com/9b88f694818c3fd387684686ba5b2cf739c9d1f2_full.jpg",
3102 "steam_id": "76561198068315512",
3103 "sp_score": 147,
3104 "mp_score": 86,
3105 "overall_score": 0,
3106 "sp_rank": 0,
3107 "mp_rank": 41,
3108 "overall_rank": 0
3109 },
3110 {
3111 "user_name": "zhendiac",
3112 "avatar_link": "https://avatars.steamstatic.com/d7d350ad47edbfa3acfe74761fe196b1d89f4e17_full.jpg",
3113 "steam_id": "76561198036324314",
3114 "sp_score": 173,
3115 "mp_score": 87,
3116 "overall_score": 0,
3117 "sp_rank": 0,
3118 "mp_rank": 42,
3119 "overall_rank": 0
3120 },
3121 {
3122 "user_name": "Barbikoru",
3123 "avatar_link": "https://avatars.steamstatic.com/7c0c327673e0f09011c96999c738652cf548e5b1_full.jpg",
3124 "steam_id": "76561198324155905",
3125 "sp_score": 67,
3126 "mp_score": 89,
3127 "overall_score": 0,
3128 "sp_rank": 0,
3129 "mp_rank": 43,
3130 "overall_rank": 0
3131 },
3132 {
3133 "user_name": "ki4rakaM [RUS]",
3134 "avatar_link": "https://avatars.steamstatic.com/cae7d5a1e4b04f70dc0c1599d932edb423e65870_full.jpg",
3135 "steam_id": "76561198227911092",
3136 "sp_score": 157,
3137 "mp_score": 89,
3138 "overall_score": 246,
3139 "sp_rank": 74,
3140 "mp_rank": 43,
3141 "overall_rank": 56
3142 },
3143 {
3144 "user_name": "Mister Man",
3145 "avatar_link": "https://avatars.steamstatic.com/695d7049640bded587ed3f5a83c26f1a1ad9c879_full.jpg",
3146 "steam_id": "76561197980620221",
3147 "sp_score": 72,
3148 "mp_score": 89,
3149 "overall_score": 0,
3150 "sp_rank": 0,
3151 "mp_rank": 43,
3152 "overall_rank": 0
3153 },
3154 {
3155 "user_name": "badger",
3156 "avatar_link": "https://avatars.steamstatic.com/cbea4cfe87dab41ed9d2b53be876110b98e4111a_full.jpg",
3157 "steam_id": "76561198861024091",
3158 "sp_score": 135,
3159 "mp_score": 89,
3160 "overall_score": 224,
3161 "sp_rank": 55,
3162 "mp_rank": 43,
3163 "overall_rank": 50
3164 },
3165 {
3166 "user_name": "Hacked Exhale",
3167 "avatar_link": "https://avatars.steamstatic.com/3d5a750f0fb2ac21ff46ceea973ef8b2eee2bff8_full.jpg",
3168 "steam_id": "76561197978601137",
3169 "sp_score": 55,
3170 "mp_score": 90,
3171 "overall_score": 0,
3172 "sp_rank": 0,
3173 "mp_rank": 44,
3174 "overall_rank": 0
3175 },
3176 {
3177 "user_name": "Kendal",
3178 "avatar_link": "https://avatars.steamstatic.com/5fa6ab9276be48f30e371baa45dee39c66811f37_full.jpg",
3179 "steam_id": "76561198068358920",
3180 "sp_score": 161,
3181 "mp_score": 92,
3182 "overall_score": 0,
3183 "sp_rank": 0,
3184 "mp_rank": 45,
3185 "overall_rank": 0
3186 },
3187 {
3188 "user_name": "MegaWaTT",
3189 "avatar_link": "https://avatars.steamstatic.com/ed56d8fc9c49a77d3f8c8bd6cc3efa72e714b54d_full.jpg",
3190 "steam_id": "76561198363863187",
3191 "sp_score": 137,
3192 "mp_score": 92,
3193 "overall_score": 229,
3194 "sp_rank": 57,
3195 "mp_rank": 45,
3196 "overall_rank": 51
3197 },
3198 {
3199 "user_name": "Lemmons",
3200 "avatar_link": "https://avatars.steamstatic.com/251093b6b46199072eef6a2bb8f95c1f3ec8770d_full.jpg",
3201 "steam_id": "76561198182774873",
3202 "sp_score": 2,
3203 "mp_score": 94,
3204 "overall_score": 0,
3205 "sp_rank": 0,
3206 "mp_rank": 46,
3207 "overall_rank": 0
3208 },
3209 {
3210 "user_name": "iVerb",
3211 "avatar_link": "https://avatars.steamstatic.com/1acc820cbf4e724190db676db26202ec2049098e_full.jpg",
3212 "steam_id": "76561198047900528",
3213 "sp_score": 158,
3214 "mp_score": 95,
3215 "overall_score": 0,
3216 "sp_rank": 0,
3217 "mp_rank": 47,
3218 "overall_rank": 0
3219 },
3220 {
3221 "user_name": "expo",
3222 "avatar_link": "https://avatars.steamstatic.com/a17401681c8249a538d41142bca7e745bf47480a_full.jpg",
3223 "steam_id": "76561198075953991",
3224 "sp_score": 127,
3225 "mp_score": 96,
3226 "overall_score": 0,
3227 "sp_rank": 0,
3228 "mp_rank": 48,
3229 "overall_rank": 0
3230 },
3231 {
3232 "user_name": "XTLmaker",
3233 "avatar_link": "https://avatars.steamstatic.com/b3c041f3eb316e0edf16e6ba36f426b433e16cee_full.jpg",
3234 "steam_id": "76561199032030834",
3235 "sp_score": 134,
3236 "mp_score": 97,
3237 "overall_score": 231,
3238 "sp_rank": 54,
3239 "mp_rank": 49,
3240 "overall_rank": 53
3241 },
3242 {
3243 "user_name": "Spyrunite",
3244 "avatar_link": "https://avatars.steamstatic.com/184e99f06e36b81346214c37f6b448f4d71fcb8b_full.jpg",
3245 "steam_id": "76561198026851335",
3246 "sp_score": 132,
3247 "mp_score": 98,
3248 "overall_score": 230,
3249 "sp_rank": 52,
3250 "mp_rank": 50,
3251 "overall_rank": 52
3252 },
3253 {
3254 "user_name": "SilentiumGradas",
3255 "avatar_link": "https://avatars.steamstatic.com/b26b46bc2dd6efece8b6cbcff8ba263801b5b6dc_full.jpg",
3256 "steam_id": "76561199006050430",
3257 "sp_score": 142,
3258 "mp_score": 101,
3259 "overall_score": 243,
3260 "sp_rank": 62,
3261 "mp_rank": 51,
3262 "overall_rank": 55
3263 },
3264 {
3265 "user_name": "hazza",
3266 "avatar_link": "https://avatars.steamstatic.com/5a9e8d6229e67c253695136f2fee087f04b5ec05_full.jpg",
3267 "steam_id": "76561198039912258",
3268 "sp_score": 133,
3269 "mp_score": 101,
3270 "overall_score": 0,
3271 "sp_rank": 0,
3272 "mp_rank": 51,
3273 "overall_rank": 0
3274 },
3275 {
3276 "user_name": "Schlepian",
3277 "avatar_link": "https://avatars.steamstatic.com/f7be9949784d7864c619a72e0bec1138a14933ff_full.jpg",
3278 "steam_id": "76561198021734854",
3279 "sp_score": 161,
3280 "mp_score": 105,
3281 "overall_score": 266,
3282 "sp_rank": 76,
3283 "mp_rank": 52,
3284 "overall_rank": 58
3285 },
3286 {
3287 "user_name": "Schlay",
3288 "avatar_link": "https://avatars.steamstatic.com/1c81f34080417cab9a836c003e5c319229e528f9_full.jpg",
3289 "steam_id": "76561198042995537",
3290 "sp_score": 170,
3291 "mp_score": 108,
3292 "overall_score": 278,
3293 "sp_rank": 82,
3294 "mp_rank": 53,
3295 "overall_rank": 59
3296 },
3297 {
3298 "user_name": "Bubblegum Cuddly Dragoness",
3299 "avatar_link": "https://avatars.steamstatic.com/52aaae46baa3eb09ad16a15756c0c0e707792979_full.jpg",
3300 "steam_id": "76561198171146837",
3301 "sp_score": 2,
3302 "mp_score": 108,
3303 "overall_score": 0,
3304 "sp_rank": 0,
3305 "mp_rank": 53,
3306 "overall_rank": 0
3307 },
3308 {
3309 "user_name": "LamboLord24",
3310 "avatar_link": "https://avatars.steamstatic.com/17b9acd5b3f12ad9ccc1b13185b6dec6e127422d_full.jpg",
3311 "steam_id": "76561198263749501",
3312 "sp_score": 163,
3313 "mp_score": 109,
3314 "overall_score": 0,
3315 "sp_rank": 0,
3316 "mp_rank": 54,
3317 "overall_rank": 0
3318 },
3319 {
3320 "user_name": "«✮ঔৣ Akumaঔৣ✮»",
3321 "avatar_link": "https://avatars.steamstatic.com/466713b1c71a6f4bb173801ce86aa7a09085744e_full.jpg",
3322 "steam_id": "76561198809780104",
3323 "sp_score": 54,
3324 "mp_score": 110,
3325 "overall_score": 0,
3326 "sp_rank": 0,
3327 "mp_rank": 55,
3328 "overall_rank": 0
3329 },
3330 {
3331 "user_name": "Bdiggles",
3332 "avatar_link": "https://avatars.steamstatic.com/fb16ca8a8afa49b290cbe0825411052e8fa19f86_full.jpg",
3333 "steam_id": "76561198072337331",
3334 "sp_score": 85,
3335 "mp_score": 111,
3336 "overall_score": 0,
3337 "sp_rank": 0,
3338 "mp_rank": 56,
3339 "overall_rank": 0
3340 },
3341 {
3342 "user_name": "juan",
3343 "avatar_link": "https://avatars.steamstatic.com/92b4051d048561796489cf256bb5eafa7302a85f_full.jpg",
3344 "steam_id": "76561198170811613",
3345 "sp_score": 2,
3346 "mp_score": 111,
3347 "overall_score": 0,
3348 "sp_rank": 0,
3349 "mp_rank": 56,
3350 "overall_rank": 0
3351 },
3352 {
3353 "user_name": "Betsruner",
3354 "avatar_link": "https://avatars.steamstatic.com/6e5b5f43361149652d556073c34a4c3bd5c56df2_full.jpg",
3355 "steam_id": "76561198048179892",
3356 "sp_score": 153,
3357 "mp_score": 113,
3358 "overall_score": 266,
3359 "sp_rank": 70,
3360 "mp_rank": 57,
3361 "overall_rank": 58
3362 },
3363 {
3364 "user_name": "Led_Astray",
3365 "avatar_link": "https://avatars.steamstatic.com/26458ac0a9e4a290b2edc09801b09e92ab74a747_full.jpg",
3366 "steam_id": "76561198125215858",
3367 "sp_score": 154,
3368 "mp_score": 113,
3369 "overall_score": 0,
3370 "sp_rank": 0,
3371 "mp_rank": 57,
3372 "overall_rank": 0
3373 },
3374 {
3375 "user_name": "Phantom",
3376 "avatar_link": "https://avatars.steamstatic.com/06a00384bc8140f425cf81ac6637222620ef9307_full.jpg",
3377 "steam_id": "76561198058087062",
3378 "sp_score": 169,
3379 "mp_score": 115,
3380 "overall_score": 0,
3381 "sp_rank": 0,
3382 "mp_rank": 58,
3383 "overall_rank": 0
3384 },
3385 {
3386 "user_name": "svo",
3387 "avatar_link": "https://avatars.steamstatic.com/b10f98132d4c19cf862ed0630e73112f7bf272f7_full.jpg",
3388 "steam_id": "76561198025422567",
3389 "sp_score": 55,
3390 "mp_score": 117,
3391 "overall_score": 0,
3392 "sp_rank": 0,
3393 "mp_rank": 59,
3394 "overall_rank": 0
3395 },
3396 {
3397 "user_name": "Below average player",
3398 "avatar_link": "https://avatars.steamstatic.com/0e1e69fb2542d5a971b6e8a98a6c045df537764e_full.jpg",
3399 "steam_id": "76561198119082730",
3400 "sp_score": 33,
3401 "mp_score": 120,
3402 "overall_score": 0,
3403 "sp_rank": 0,
3404 "mp_rank": 60,
3405 "overall_rank": 0
3406 },
3407 {
3408 "user_name": "Can't Even",
3409 "avatar_link": "https://avatars.steamstatic.com/4afaebb9ddc55f39e0b8b8e4a25a21d7eac6c574_full.jpg",
3410 "steam_id": "76561198093441459",
3411 "sp_score": 135,
3412 "mp_score": 121,
3413 "overall_score": 0,
3414 "sp_rank": 0,
3415 "mp_rank": 61,
3416 "overall_rank": 0
3417 },
3418 {
3419 "user_name": "spidda",
3420 "avatar_link": "https://avatars.steamstatic.com/31f788519863b79f24b1604e090596ba6961a3ab_full.jpg",
3421 "steam_id": "76561198057436685",
3422 "sp_score": 148,
3423 "mp_score": 121,
3424 "overall_score": 0,
3425 "sp_rank": 0,
3426 "mp_rank": 61,
3427 "overall_rank": 0
3428 },
3429 {
3430 "user_name": "kerzenkaktus",
3431 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
3432 "steam_id": "76561198255545050",
3433 "sp_score": 139,
3434 "mp_score": 122,
3435 "overall_score": 0,
3436 "sp_rank": 0,
3437 "mp_rank": 62,
3438 "overall_rank": 0
3439 },
3440 {
3441 "user_name": "RaspeRuben",
3442 "avatar_link": "https://avatars.steamstatic.com/ff8cce6ed65259baf9e43ccb0a19f4eb23ba5151_full.jpg",
3443 "steam_id": "76561198045034733",
3444 "sp_score": 137,
3445 "mp_score": 124,
3446 "overall_score": 0,
3447 "sp_rank": 0,
3448 "mp_rank": 63,
3449 "overall_rank": 0
3450 },
3451 {
3452 "user_name": "¯\\_(ツ)_/¯",
3453 "avatar_link": "https://avatars.steamstatic.com/fb9c36c36e54b8ca5f2e1cbd89c06574d1348af0_full.jpg",
3454 "steam_id": "76561198001523094",
3455 "sp_score": 175,
3456 "mp_score": 127,
3457 "overall_score": 302,
3458 "sp_rank": 83,
3459 "mp_rank": 64,
3460 "overall_rank": 60
3461 },
3462 {
3463 "user_name": "daver12345",
3464 "avatar_link": "https://avatars.steamstatic.com/544a1f05dff94e62346a7c05af4fd7073389fd78_full.jpg",
3465 "steam_id": "76561198101504119",
3466 "sp_score": 159,
3467 "mp_score": 128,
3468 "overall_score": 0,
3469 "sp_rank": 0,
3470 "mp_rank": 65,
3471 "overall_rank": 0
3472 },
3473 {
3474 "user_name": "Impossibear",
3475 "avatar_link": "https://avatars.steamstatic.com/4be16de2b923be8ced14e4235bcac95d873aa492_full.jpg",
3476 "steam_id": "76561198050446845",
3477 "sp_score": 155,
3478 "mp_score": 129,
3479 "overall_score": 0,
3480 "sp_rank": 0,
3481 "mp_rank": 66,
3482 "overall_rank": 0
3483 },
3484 {
3485 "user_name": "hero",
3486 "avatar_link": "https://avatars.steamstatic.com/b5a35d5b26f9124593201b185c00ebd0efac775d_full.jpg",
3487 "steam_id": "76561198254956991",
3488 "sp_score": 142,
3489 "mp_score": 129,
3490 "overall_score": 0,
3491 "sp_rank": 0,
3492 "mp_rank": 66,
3493 "overall_rank": 0
3494 },
3495 {
3496 "user_name": "neeeklaus",
3497 "avatar_link": "https://avatars.steamstatic.com/1b5a627d003062ba15236ca9b306ae56067ea310_full.jpg",
3498 "steam_id": "76561198098168066",
3499 "sp_score": 51,
3500 "mp_score": 129,
3501 "overall_score": 0,
3502 "sp_rank": 0,
3503 "mp_rank": 66,
3504 "overall_rank": 0
3505 },
3506 {
3507 "user_name": "GhOsTLySwArM",
3508 "avatar_link": "https://avatars.steamstatic.com/4ab3db0761bdfb0b02c32de00e0924e1270cf81a_full.jpg",
3509 "steam_id": "76561198871800785",
3510 "sp_score": 4,
3511 "mp_score": 144,
3512 "overall_score": 0,
3513 "sp_rank": 0,
3514 "mp_rank": 67,
3515 "overall_rank": 0
3516 },
3517 {
3518 "user_name": "пивной дезертир",
3519 "avatar_link": "https://avatars.steamstatic.com/670eb37891a5cfaca8b99be2150e78b1acdd3aae_full.jpg",
3520 "steam_id": "76561198415120970",
3521 "sp_score": 159,
3522 "mp_score": 147,
3523 "overall_score": 0,
3524 "sp_rank": 0,
3525 "mp_rank": 68,
3526 "overall_rank": 0
3527 },
3528 {
3529 "user_name": "Dodecahedrony",
3530 "avatar_link": "https://avatars.steamstatic.com/7183bb63deabd70d15a5ee7b33faf317df8763c2_full.jpg",
3531 "steam_id": "76561198316957058",
3532 "sp_score": 156,
3533 "mp_score": 149,
3534 "overall_score": 0,
3535 "sp_rank": 0,
3536 "mp_rank": 69,
3537 "overall_rank": 0
3538 },
3539 {
3540 "user_name": "Ninja Driedel",
3541 "avatar_link": "https://avatars.steamstatic.com/ea548dd7c2dad0cf98d538611e7bba0ff5bfa936_full.jpg",
3542 "steam_id": "76561199087474545",
3543 "sp_score": 77,
3544 "mp_score": 149,
3545 "overall_score": 0,
3546 "sp_rank": 0,
3547 "mp_rank": 69,
3548 "overall_rank": 0
3549 },
3550 {
3551 "user_name": "Virken",
3552 "avatar_link": "https://avatars.steamstatic.com/71217cc54fc8da62a8c843c0f527ab60405fc06b_full.jpg",
3553 "steam_id": "76561198130509300",
3554 "sp_score": 160,
3555 "mp_score": 151,
3556 "overall_score": 0,
3557 "sp_rank": 0,
3558 "mp_rank": 70,
3559 "overall_rank": 0
3560 },
3561 {
3562 "user_name": "Rex",
3563 "avatar_link": "https://avatars.steamstatic.com/3b161f8a37d8e69c3244b7c23d7b461433e14c0c_full.jpg",
3564 "steam_id": "76561198095730281",
3565 "sp_score": 142,
3566 "mp_score": 151,
3567 "overall_score": 0,
3568 "sp_rank": 0,
3569 "mp_rank": 70,
3570 "overall_rank": 0
3571 },
3572 {
3573 "user_name": "mitya",
3574 "avatar_link": "https://avatars.steamstatic.com/c774fcb7516d344037f0b6abc8a26f9619202081_full.jpg",
3575 "steam_id": "76561198377664123",
3576 "sp_score": 139,
3577 "mp_score": 154,
3578 "overall_score": 0,
3579 "sp_rank": 0,
3580 "mp_rank": 71,
3581 "overall_rank": 0
3582 },
3583 {
3584 "user_name": "Swiftrax",
3585 "avatar_link": "https://avatars.steamstatic.com/938f2ed6557cb0637293a2e24b86870b8a648406_full.jpg",
3586 "steam_id": "76561198041962842",
3587 "sp_score": 159,
3588 "mp_score": 159,
3589 "overall_score": 0,
3590 "sp_rank": 0,
3591 "mp_rank": 72,
3592 "overall_rank": 0
3593 },
3594 {
3595 "user_name": "Flower_H0rse",
3596 "avatar_link": "https://avatars.steamstatic.com/a6ba3b4fff2fc30a596f227fa7f31000fd8efb97_full.jpg",
3597 "steam_id": "76561199227965499",
3598 "sp_score": 127,
3599 "mp_score": 161,
3600 "overall_score": 0,
3601 "sp_rank": 0,
3602 "mp_rank": 73,
3603 "overall_rank": 0
3604 },
3605 {
3606 "user_name": "Dane",
3607 "avatar_link": "https://avatars.steamstatic.com/88575483645036637ac0f8568d8a7ffbbb658dd6_full.jpg",
3608 "steam_id": "76561198057501496",
3609 "sp_score": 153,
3610 "mp_score": 161,
3611 "overall_score": 0,
3612 "sp_rank": 0,
3613 "mp_rank": 73,
3614 "overall_rank": 0
3615 },
3616 {
3617 "user_name": "しの",
3618 "avatar_link": "https://avatars.steamstatic.com/cca88f25df7d64ff52c26b95d9454a0af274957c_full.jpg",
3619 "steam_id": "76561198814954135",
3620 "sp_score": 6,
3621 "mp_score": 163,
3622 "overall_score": 0,
3623 "sp_rank": 0,
3624 "mp_rank": 74,
3625 "overall_rank": 0
3626 },
3627 {
3628 "user_name": "eszter",
3629 "avatar_link": "https://avatars.steamstatic.com/9e382a566d3fc7425cb39e4f97535cda2251e219_full.jpg",
3630 "steam_id": "76561198044618353",
3631 "sp_score": 212,
3632 "mp_score": 163,
3633 "overall_score": 0,
3634 "sp_rank": 0,
3635 "mp_rank": 74,
3636 "overall_rank": 0
3637 },
3638 {
3639 "user_name": "skittle chan",
3640 "avatar_link": "https://avatars.steamstatic.com/1cde41417aa40729a6228de08240153e5b36b244_full.jpg",
3641 "steam_id": "76561199426450565",
3642 "sp_score": 167,
3643 "mp_score": 165,
3644 "overall_score": 0,
3645 "sp_rank": 0,
3646 "mp_rank": 75,
3647 "overall_rank": 0
3648 },
3649 {
3650 "user_name": "EDDY SPAGHETTI DANK MEMES",
3651 "avatar_link": "https://avatars.steamstatic.com/8e491e9416f9170433517b5dba0223c98c4b65d7_full.jpg",
3652 "steam_id": "76561198064465940",
3653 "sp_score": 156,
3654 "mp_score": 167,
3655 "overall_score": 0,
3656 "sp_rank": 0,
3657 "mp_rank": 76,
3658 "overall_rank": 0
3659 },
3660 {
3661 "user_name": "AJ",
3662 "avatar_link": "https://avatars.steamstatic.com/7de1994882e6532f9226de20b3d31bfe8ff12095_full.jpg",
3663 "steam_id": "76561198035130516",
3664 "sp_score": 147,
3665 "mp_score": 168,
3666 "overall_score": 0,
3667 "sp_rank": 0,
3668 "mp_rank": 77,
3669 "overall_rank": 0
3670 },
3671 {
3672 "user_name": "kyツ",
3673 "avatar_link": "https://avatars.steamstatic.com/a4b039ebd4ea911f9e6715f3c7949148b3ce1812_full.jpg",
3674 "steam_id": "76561198041349990",
3675 "sp_score": 170,
3676 "mp_score": 178,
3677 "overall_score": 0,
3678 "sp_rank": 0,
3679 "mp_rank": 78,
3680 "overall_rank": 0
3681 },
3682 {
3683 "user_name": "Faithless",
3684 "avatar_link": "https://avatars.steamstatic.com/aebacfe8919403fe0ecc0c4e50b3f67d97c6d620_full.jpg",
3685 "steam_id": "76561197980492609",
3686 "sp_score": 0,
3687 "mp_score": 184,
3688 "overall_score": 0,
3689 "sp_rank": 0,
3690 "mp_rank": 79,
3691 "overall_rank": 0
3692 },
3693 {
3694 "user_name": "Keyser",
3695 "avatar_link": "https://avatars.steamstatic.com/14c7c4d9634a94cfa8f8b1141e3187adbfa4774a_full.jpg",
3696 "steam_id": "76561197969927537",
3697 "sp_score": 61,
3698 "mp_score": 184,
3699 "overall_score": 0,
3700 "sp_rank": 0,
3701 "mp_rank": 79,
3702 "overall_rank": 0
3703 },
3704 {
3705 "user_name": "|lDgAl|HeXeRMaN",
3706 "avatar_link": "https://avatars.steamstatic.com/0361f4990419a90fcc53a228541b2b8749bfceda_full.jpg",
3707 "steam_id": "76561197980522591",
3708 "sp_score": 183,
3709 "mp_score": 184,
3710 "overall_score": 0,
3711 "sp_rank": 0,
3712 "mp_rank": 79,
3713 "overall_rank": 0
3714 },
3715 {
3716 "user_name": "Gigo",
3717 "avatar_link": "https://avatars.steamstatic.com/f4bc4f53d66559f5889cddfd4c4af00c0f22e714_full.jpg",
3718 "steam_id": "76561198004871206",
3719 "sp_score": 131,
3720 "mp_score": 193,
3721 "overall_score": 0,
3722 "sp_rank": 0,
3723 "mp_rank": 80,
3724 "overall_rank": 0
3725 },
3726 {
3727 "user_name": "lampishboi",
3728 "avatar_link": "https://avatars.steamstatic.com/22bc948278437707cf69cc70a153f8363c95bccf_full.jpg",
3729 "steam_id": "76561198994808916",
3730 "sp_score": 131,
3731 "mp_score": 199,
3732 "overall_score": 330,
3733 "sp_rank": 51,
3734 "mp_rank": 81,
3735 "overall_rank": 61
3736 },
3737 {
3738 "user_name": "mr.deagle",
3739 "avatar_link": "https://avatars.steamstatic.com/ca9843d4e194905f7b8106dc4cdc046587b67303_full.jpg",
3740 "steam_id": "76561197970314683",
3741 "sp_score": 85,
3742 "mp_score": 199,
3743 "overall_score": 0,
3744 "sp_rank": 0,
3745 "mp_rank": 81,
3746 "overall_rank": 0
3747 },
3748 {
3749 "user_name": "Chris",
3750 "avatar_link": "https://avatars.steamstatic.com/83cbe3c40465ebda03b53b9ada61bb87e374a08d_full.jpg",
3751 "steam_id": "76561198036794680",
3752 "sp_score": 61,
3753 "mp_score": 201,
3754 "overall_score": 0,
3755 "sp_rank": 0,
3756 "mp_rank": 82,
3757 "overall_rank": 0
3758 },
3759 {
3760 "user_name": "Jimmy",
3761 "avatar_link": "https://avatars.steamstatic.com/26c52b8af4195235c8b791097fb34e64c8b631bb_full.jpg",
3762 "steam_id": "76561198046543307",
3763 "sp_score": 4,
3764 "mp_score": 201,
3765 "overall_score": 0,
3766 "sp_rank": 0,
3767 "mp_rank": 82,
3768 "overall_rank": 0
3769 },
3770 {
3771 "user_name": "Glost999",
3772 "avatar_link": "https://avatars.steamstatic.com/f95c03592d1c4250a6ce3816dd1105da18ed3eaf_full.jpg",
3773 "steam_id": "76561198042671991",
3774 "sp_score": 134,
3775 "mp_score": 202,
3776 "overall_score": 0,
3777 "sp_rank": 0,
3778 "mp_rank": 83,
3779 "overall_rank": 0
3780 },
3781 {
3782 "user_name": "Tharsic",
3783 "avatar_link": "https://avatars.steamstatic.com/119b34225d2abf2e1ca84d0122197a2f013329b5_full.jpg",
3784 "steam_id": "76561197976665233",
3785 "sp_score": 253,
3786 "mp_score": 203,
3787 "overall_score": 0,
3788 "sp_rank": 0,
3789 "mp_rank": 84,
3790 "overall_rank": 0
3791 },
3792 {
3793 "user_name": "rugcer",
3794 "avatar_link": "https://avatars.steamstatic.com/85a853daef3a8766f4b3767f2146dbd043daa1fa_full.jpg",
3795 "steam_id": "76561198063407806",
3796 "sp_score": 34,
3797 "mp_score": 203,
3798 "overall_score": 0,
3799 "sp_rank": 0,
3800 "mp_rank": 84,
3801 "overall_rank": 0
3802 },
3803 {
3804 "user_name": "Msushi",
3805 "avatar_link": "https://avatars.steamstatic.com/ac135680e1efc673882dd74081e11c1810be9b40_full.jpg",
3806 "steam_id": "76561198048636382",
3807 "sp_score": 148,
3808 "mp_score": 203,
3809 "overall_score": 0,
3810 "sp_rank": 0,
3811 "mp_rank": 84,
3812 "overall_rank": 0
3813 },
3814 {
3815 "user_name": "『 Jonese1234 』",
3816 "avatar_link": "https://avatars.steamstatic.com/9f6de098624a8f81ba6d2318e1923bdda1c710d6_full.jpg",
3817 "steam_id": "76561198045074889",
3818 "sp_score": 157,
3819 "mp_score": 206,
3820 "overall_score": 363,
3821 "sp_rank": 74,
3822 "mp_rank": 85,
3823 "overall_rank": 62
3824 },
3825 {
3826 "user_name": "Markel",
3827 "avatar_link": "https://avatars.steamstatic.com/ce4ddba52f445c0eb71ddca800bfd5bf6ed332f3_full.jpg",
3828 "steam_id": "76561198043196429",
3829 "sp_score": 178,
3830 "mp_score": 207,
3831 "overall_score": 0,
3832 "sp_rank": 0,
3833 "mp_rank": 86,
3834 "overall_rank": 0
3835 },
3836 {
3837 "user_name": "Retep",
3838 "avatar_link": "https://avatars.steamstatic.com/5f6efd223eef4b1801a8ef0b817e20126d9615d2_full.jpg",
3839 "steam_id": "76561198052457191",
3840 "sp_score": 185,
3841 "mp_score": 208,
3842 "overall_score": 0,
3843 "sp_rank": 0,
3844 "mp_rank": 87,
3845 "overall_rank": 0
3846 },
3847 {
3848 "user_name": "Potatoes",
3849 "avatar_link": "https://avatars.steamstatic.com/94821c98d19e5eda6ec315289aa28b191084f301_full.jpg",
3850 "steam_id": "76561197974561284",
3851 "sp_score": 248,
3852 "mp_score": 209,
3853 "overall_score": 457,
3854 "sp_rank": 89,
3855 "mp_rank": 88,
3856 "overall_rank": 63
3857 },
3858 {
3859 "user_name": "LotsOfS",
3860 "avatar_link": "https://avatars.steamstatic.com/4bf4213eda8c7862b9c58a0a02ea3ddbcc52a321_full.jpg",
3861 "steam_id": "76561197972803163",
3862 "sp_score": 231,
3863 "mp_score": 211,
3864 "overall_score": 0,
3865 "sp_rank": 0,
3866 "mp_rank": 89,
3867 "overall_rank": 0
3868 },
3869 {
3870 "user_name": "SIMOON ✈",
3871 "avatar_link": "https://avatars.steamstatic.com/1c0b5c37a442a2d39f32902ec42f2e26ba6a142e_full.jpg",
3872 "steam_id": "76561197976463017",
3873 "sp_score": 268,
3874 "mp_score": 212,
3875 "overall_score": 0,
3876 "sp_rank": 0,
3877 "mp_rank": 90,
3878 "overall_rank": 0
3879 },
3880 {
3881 "user_name": "Drast くコ:彡",
3882 "avatar_link": "https://avatars.steamstatic.com/18e2cf5be81bed1ced5dd4ea9c71ff7e15fa492f_full.jpg",
3883 "steam_id": "76561198039154239",
3884 "sp_score": 7,
3885 "mp_score": 218,
3886 "overall_score": 0,
3887 "sp_rank": 0,
3888 "mp_rank": 91,
3889 "overall_rank": 0
3890 },
3891 {
3892 "user_name": "董美龄",
3893 "avatar_link": "https://avatars.steamstatic.com/783100335395646d0cfc75cba6d84ae5013f6dff_full.jpg",
3894 "steam_id": "76561198067468981",
3895 "sp_score": 161,
3896 "mp_score": 218,
3897 "overall_score": 0,
3898 "sp_rank": 0,
3899 "mp_rank": 91,
3900 "overall_rank": 0
3901 },
3902 {
3903 "user_name": "Trox",
3904 "avatar_link": "https://avatars.steamstatic.com/dc2f96da104aef42ae74161a29d2e0f08f0a35fd_full.jpg",
3905 "steam_id": "76561197976665231",
3906 "sp_score": 104,
3907 "mp_score": 220,
3908 "overall_score": 0,
3909 "sp_rank": 0,
3910 "mp_rank": 92,
3911 "overall_rank": 0
3912 },
3913 {
3914 "user_name": "Viviatron",
3915 "avatar_link": "https://avatars.steamstatic.com/8c16194bab99c6977289de5e7100a2aeb3aa889b_full.jpg",
3916 "steam_id": "76561198257444100",
3917 "sp_score": 162,
3918 "mp_score": 222,
3919 "overall_score": 0,
3920 "sp_rank": 0,
3921 "mp_rank": 93,
3922 "overall_rank": 0
3923 },
3924 {
3925 "user_name": "I am lost",
3926 "avatar_link": "https://avatars.steamstatic.com/8feb46d792dde9d9d27000c153f15516e5ff6f92_full.jpg",
3927 "steam_id": "76561198208183016",
3928 "sp_score": 121,
3929 "mp_score": 223,
3930 "overall_score": 0,
3931 "sp_rank": 0,
3932 "mp_rank": 94,
3933 "overall_rank": 0
3934 },
3935 {
3936 "user_name": "Pog",
3937 "avatar_link": "https://avatars.steamstatic.com/f805f0859795fa061f2a8d2649ce16f12021de45_full.jpg",
3938 "steam_id": "76561199051251085",
3939 "sp_score": 11,
3940 "mp_score": 228,
3941 "overall_score": 0,
3942 "sp_rank": 0,
3943 "mp_rank": 95,
3944 "overall_rank": 0
3945 },
3946 {
3947 "user_name": "pain",
3948 "avatar_link": "https://avatars.steamstatic.com/343dab39597de5d25d02eab2b2fe48d8dde6ae0e_full.jpg",
3949 "steam_id": "76561198025894860",
3950 "sp_score": 225,
3951 "mp_score": 229,
3952 "overall_score": 0,
3953 "sp_rank": 0,
3954 "mp_rank": 96,
3955 "overall_rank": 0
3956 },
3957 {
3958 "user_name": "PiorkoSky",
3959 "avatar_link": "https://avatars.steamstatic.com/97caee00eb9e2fd9f78eaf034b7f9f4d2fd9210d_full.jpg",
3960 "steam_id": "76561198040941119",
3961 "sp_score": 178,
3962 "mp_score": 229,
3963 "overall_score": 0,
3964 "sp_rank": 0,
3965 "mp_rank": 96,
3966 "overall_rank": 0
3967 },
3968 {
3969 "user_name": "Setharu",
3970 "avatar_link": "https://avatars.steamstatic.com/bc7182674746a2a26f20c4be3fc1b529ae68aa91_full.jpg",
3971 "steam_id": "76561198019599030",
3972 "sp_score": 92,
3973 "mp_score": 238,
3974 "overall_score": 0,
3975 "sp_rank": 0,
3976 "mp_rank": 97,
3977 "overall_rank": 0
3978 },
3979 {
3980 "user_name": "dawn",
3981 "avatar_link": "https://avatars.steamstatic.com/190751663ac28b9dac167347337bceea34a0c59f_full.jpg",
3982 "steam_id": "76561197960285145",
3983 "sp_score": 88,
3984 "mp_score": 259,
3985 "overall_score": 0,
3986 "sp_rank": 0,
3987 "mp_rank": 98,
3988 "overall_rank": 0
3989 },
3990 {
3991 "user_name": "Petieken",
3992 "avatar_link": "https://avatars.steamstatic.com/0d0f89bd4df398d7ff7b4e253625d120949d1049_full.jpg",
3993 "steam_id": "76561197965344508",
3994 "sp_score": 0,
3995 "mp_score": 272,
3996 "overall_score": 0,
3997 "sp_rank": 0,
3998 "mp_rank": 99,
3999 "overall_rank": 0
4000 },
4001 {
4002 "user_name": "S",
4003 "avatar_link": "https://avatars.steamstatic.com/9aec167e64de72c34ede2e4196e3eef912e92f43_full.jpg",
4004 "steam_id": "76561197973861204",
4005 "sp_score": 34,
4006 "mp_score": 282,
4007 "overall_score": 0,
4008 "sp_rank": 0,
4009 "mp_rank": 100,
4010 "overall_rank": 0
4011 },
4012 {
4013 "user_name": "nairolF",
4014 "avatar_link": "https://avatars.steamstatic.com/3f6e63089b13c395372cb0fd45be258332024e33_full.jpg",
4015 "steam_id": "76561197964814707",
4016 "sp_score": 34,
4017 "mp_score": 366,
4018 "overall_score": 0,
4019 "sp_rank": 0,
4020 "mp_rank": 101,
4021 "overall_rank": 0
4022 },
4023 {
4024 "user_name": "unNamed",
4025 "avatar_link": "https://avatars.steamstatic.com/d956bc4013e234d687e01e910297bd80cde68345_full.jpg",
4026 "steam_id": "76561197964995786",
4027 "sp_score": 9,
4028 "mp_score": 390,
4029 "overall_score": 0,
4030 "sp_rank": 0,
4031 "mp_rank": 102,
4032 "overall_rank": 0
4033 }
4034 ],
4035 "rankings_overall": [
4036 {
4037 "user_name": "SuperAiderton",
4038 "avatar_link": "https://avatars.steamstatic.com/a19aca196dbb75b51b83fe7d06b0b7fce0f894b2_full.jpg",
4039 "steam_id": "76561199069631083",
4040 "sp_score": 65,
4041 "mp_score": 48,
4042 "overall_score": 113,
4043 "sp_rank": 1,
4044 "mp_rank": 7,
4045 "overall_rank": 1
4046 },
4047 {
4048 "user_name": "Nidboj132",
4049 "avatar_link": "https://avatars.steamstatic.com/07bc99e768c9f640979e2a393f28306a32fa796e_full.jpg",
4050 "steam_id": "76561198337970645",
4051 "sp_score": 76,
4052 "mp_score": 41,
4053 "overall_score": 117,
4054 "sp_rank": 4,
4055 "mp_rank": 1,
4056 "overall_rank": 2
4057 },
4058 {
4059 "user_name": "mOtYl",
4060 "avatar_link": "https://avatars.steamstatic.com/8065f6018757dc0ee927d2279ccf7e8ab7827109_full.jpg",
4061 "steam_id": "76561197994700458",
4062 "sp_score": 74,
4063 "mp_score": 49,
4064 "overall_score": 123,
4065 "sp_rank": 3,
4066 "mp_rank": 8,
4067 "overall_rank": 3
4068 },
4069 {
4070 "user_name": "?",
4071 "avatar_link": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg",
4072 "steam_id": "76561198838630481",
4073 "sp_score": 80,
4074 "mp_score": 46,
4075 "overall_score": 126,
4076 "sp_rank": 6,
4077 "mp_rank": 5,
4078 "overall_rank": 4
4079 },
4080 {
4081 "user_name": "Black_Semka",
4082 "avatar_link": "https://avatars.steamstatic.com/3a6acf4e40097d9db7af432684a08b6267d2af5c_full.jpg",
4083 "steam_id": "76561198997027314",
4084 "sp_score": 85,
4085 "mp_score": 41,
4086 "overall_score": 126,
4087 "sp_rank": 10,
4088 "mp_rank": 1,
4089 "overall_rank": 4
4090 },
4091 {
4092 "user_name": "xeonic",
4093 "avatar_link": "https://avatars.steamstatic.com/7c3e67f433c90512fe6cac7278d6cb8b59d10c96_full.jpg",
4094 "steam_id": "76561198973478625",
4095 "sp_score": 82,
4096 "mp_score": 45,
4097 "overall_score": 127,
4098 "sp_rank": 8,
4099 "mp_rank": 4,
4100 "overall_rank": 5
4101 },
4102 {
4103 "user_name": "slamix",
4104 "avatar_link": "https://avatars.steamstatic.com/730aee7d3904a0f38506858ba83ebc014260ccc3_full.jpg",
4105 "steam_id": "76561198403952785",
4106 "sp_score": 81,
4107 "mp_score": 47,
4108 "overall_score": 128,
4109 "sp_rank": 7,
4110 "mp_rank": 6,
4111 "overall_rank": 6
4112 },
4113 {
4114 "user_name": "Feirune~",
4115 "avatar_link": "https://avatars.steamstatic.com/fece8c2b7c57f3eecf75897ad86609adefb7ec1a_full.jpg",
4116 "steam_id": "76561198134041367",
4117 "sp_score": 90,
4118 "mp_score": 41,
4119 "overall_score": 131,
4120 "sp_rank": 15,
4121 "mp_rank": 1,
4122 "overall_rank": 7
4123 },
4124 {
4125 "user_name": "BiSaXa",
4126 "avatar_link": "https://avatars.steamstatic.com/fa7f64c79b247c8a80cafbd6dd8033b98cc1153c_full.jpg",
4127 "steam_id": "76561198131629989",
4128 "sp_score": 87,
4129 "mp_score": 47,
4130 "overall_score": 134,
4131 "sp_rank": 12,
4132 "mp_rank": 6,
4133 "overall_rank": 8
4134 },
4135 {
4136 "user_name": "PerOculos",
4137 "avatar_link": "https://avatars.steamstatic.com/7b00906ac356806bc7bdb3815ea7c1c5b13b65a8_full.jpg",
4138 "steam_id": "76561198003223063",
4139 "sp_score": 84,
4140 "mp_score": 50,
4141 "overall_score": 134,
4142 "sp_rank": 9,
4143 "mp_rank": 9,
4144 "overall_rank": 8
4145 },
4146 {
4147 "user_name": "Robotwars1",
4148 "avatar_link": "https://avatars.steamstatic.com/ac4bc6cc73ef75f11690205b123685fd5e3a7823_full.jpg",
4149 "steam_id": "76561198129010912",
4150 "sp_score": 86,
4151 "mp_score": 49,
4152 "overall_score": 135,
4153 "sp_rank": 11,
4154 "mp_rank": 8,
4155 "overall_rank": 9
4156 },
4157 {
4158 "user_name": "Zadadaz",
4159 "avatar_link": "https://avatars.steamstatic.com/8c7bed09ce10417502477b6ca29f8257c840cab3_full.jpg",
4160 "steam_id": "76561198451680661",
4161 "sp_score": 92,
4162 "mp_score": 43,
4163 "overall_score": 135,
4164 "sp_rank": 17,
4165 "mp_rank": 2,
4166 "overall_rank": 9
4167 },
4168 {
4169 "user_name": "LittleRoi",
4170 "avatar_link": "https://avatars.steamstatic.com/c9180f93ac892fa7d078f5946239d049e987e3b6_full.jpg",
4171 "steam_id": "76561198112477703",
4172 "sp_score": 85,
4173 "mp_score": 50,
4174 "overall_score": 135,
4175 "sp_rank": 10,
4176 "mp_rank": 9,
4177 "overall_rank": 9
4178 },
4179 {
4180 "user_name": "TeePeeWee",
4181 "avatar_link": "https://avatars.steamstatic.com/4392a52e384f22c9f77b539eb4b1aa2914880cdf_full.jpg",
4182 "steam_id": "76561199239427541",
4183 "sp_score": 90,
4184 "mp_score": 48,
4185 "overall_score": 138,
4186 "sp_rank": 15,
4187 "mp_rank": 7,
4188 "overall_rank": 10
4189 },
4190 {
4191 "user_name": "(MGN)-ZGP-NIKITA",
4192 "avatar_link": "https://avatars.steamstatic.com/8a72e1ed5a29e56c24926ccb33879a544bc67b36_full.jpg",
4193 "steam_id": "76561198076017585",
4194 "sp_score": 91,
4195 "mp_score": 49,
4196 "overall_score": 140,
4197 "sp_rank": 16,
4198 "mp_rank": 8,
4199 "overall_rank": 11
4200 },
4201 {
4202 "user_name": "Krzyhau",
4203 "avatar_link": "https://avatars.steamstatic.com/f29de7f41db29526848b52c8942f727b7c70b0db_full.jpg",
4204 "steam_id": "76561198096446735",
4205 "sp_score": 89,
4206 "mp_score": 52,
4207 "overall_score": 141,
4208 "sp_rank": 14,
4209 "mp_rank": 11,
4210 "overall_rank": 12
4211 },
4212 {
4213 "user_name": "Linus",
4214 "avatar_link": "https://avatars.steamstatic.com/cfaf6917f47ca6122396f46e485a79a090f29fa0_full.jpg",
4215 "steam_id": "76561198162078579",
4216 "sp_score": 92,
4217 "mp_score": 49,
4218 "overall_score": 141,
4219 "sp_rank": 17,
4220 "mp_rank": 8,
4221 "overall_rank": 12
4222 },
4223 {
4224 "user_name": "Confusion_18",
4225 "avatar_link": "https://avatars.steamstatic.com/360236e555049f204b12d3a8685a3b9b9764ebfe_full.jpg",
4226 "steam_id": "76561198386577258",
4227 "sp_score": 91,
4228 "mp_score": 51,
4229 "overall_score": 142,
4230 "sp_rank": 16,
4231 "mp_rank": 10,
4232 "overall_rank": 13
4233 },
4234 {
4235 "user_name": "SrRageALot",
4236 "avatar_link": "https://avatars.steamstatic.com/db9c6b6761d63c640456043d864f98f58f62d750_full.jpg",
4237 "steam_id": "76561199156418931",
4238 "sp_score": 89,
4239 "mp_score": 57,
4240 "overall_score": 146,
4241 "sp_rank": 14,
4242 "mp_rank": 16,
4243 "overall_rank": 14
4244 },
4245 {
4246 "user_name": "shred",
4247 "avatar_link": "https://avatars.steamstatic.com/0216ce300d00ec193414773679db7dcd77d1cd29_full.jpg",
4248 "steam_id": "76561198025486280",
4249 "sp_score": 88,
4250 "mp_score": 59,
4251 "overall_score": 147,
4252 "sp_rank": 13,
4253 "mp_rank": 18,
4254 "overall_rank": 15
4255 },
4256 {
4257 "user_name": "Suola",
4258 "avatar_link": "https://avatars.steamstatic.com/f86dcc2d065a87a603427bb382d26e96c1d61060_full.jpg",
4259 "steam_id": "76561198917972968",
4260 "sp_score": 98,
4261 "mp_score": 50,
4262 "overall_score": 148,
4263 "sp_rank": 22,
4264 "mp_rank": 9,
4265 "overall_rank": 16
4266 },
4267 {
4268 "user_name": "マジックサラダ",
4269 "avatar_link": "https://avatars.steamstatic.com/8772186a3ab48712b6eb955a46d269b52ebda706_full.jpg",
4270 "steam_id": "76561198092289827",
4271 "sp_score": 93,
4272 "mp_score": 55,
4273 "overall_score": 148,
4274 "sp_rank": 18,
4275 "mp_rank": 14,
4276 "overall_rank": 16
4277 },
4278 {
4279 "user_name": "unity",
4280 "avatar_link": "https://avatars.steamstatic.com/1fcc7701ff71dce31965e10408d79aeb79bdf051_full.jpg",
4281 "steam_id": "76561198081168311",
4282 "sp_score": 96,
4283 "mp_score": 53,
4284 "overall_score": 149,
4285 "sp_rank": 20,
4286 "mp_rank": 12,
4287 "overall_rank": 17
4288 },
4289 {
4290 "user_name": "felkelorebel",
4291 "avatar_link": "https://avatars.steamstatic.com/b3745dd64d516fb7ce7072aaad09c93fd99c48f5_full.jpg",
4292 "steam_id": "76561198015394804",
4293 "sp_score": 108,
4294 "mp_score": 43,
4295 "overall_score": 151,
4296 "sp_rank": 31,
4297 "mp_rank": 2,
4298 "overall_rank": 18
4299 },
4300 {
4301 "user_name": "cubone",
4302 "avatar_link": "https://avatars.steamstatic.com/e285359230318e5cfb27ed688903c5350cd21075_full.jpg",
4303 "steam_id": "76561198096862334",
4304 "sp_score": 93,
4305 "mp_score": 59,
4306 "overall_score": 152,
4307 "sp_rank": 18,
4308 "mp_rank": 18,
4309 "overall_rank": 19
4310 },
4311 {
4312 "user_name": "MrCatMcFly",
4313 "avatar_link": "https://avatars.steamstatic.com/6f89591012f8f0f34cef1ecdb1c10793b0ea4bd1_full.jpg",
4314 "steam_id": "76561198168920589",
4315 "sp_score": 87,
4316 "mp_score": 66,
4317 "overall_score": 153,
4318 "sp_rank": 12,
4319 "mp_rank": 25,
4320 "overall_rank": 20
4321 },
4322 {
4323 "user_name": "bob26798",
4324 "avatar_link": "https://avatars.steamstatic.com/cb940cd751f980d8d1374a66118a43f19985a1fa_full.jpg",
4325 "steam_id": "76561198278905764",
4326 "sp_score": 107,
4327 "mp_score": 51,
4328 "overall_score": 158,
4329 "sp_rank": 30,
4330 "mp_rank": 10,
4331 "overall_rank": 21
4332 },
4333 {
4334 "user_name": "Extension",
4335 "avatar_link": "https://avatars.steamstatic.com/a647685b273a238928180573feb8135944d2795c_full.jpg",
4336 "steam_id": "76561198174735211",
4337 "sp_score": 108,
4338 "mp_score": 51,
4339 "overall_score": 159,
4340 "sp_rank": 31,
4341 "mp_rank": 10,
4342 "overall_rank": 22
4343 },
4344 {
4345 "user_name": "Herneerius",
4346 "avatar_link": "https://avatars.steamstatic.com/4879fa1c72770b2c0eaef341dc6546db13897bb5_full.jpg",
4347 "steam_id": "76561198084978888",
4348 "sp_score": 98,
4349 "mp_score": 61,
4350 "overall_score": 159,
4351 "sp_rank": 22,
4352 "mp_rank": 20,
4353 "overall_rank": 22
4354 },
4355 {
4356 "user_name": "Extension",
4357 "avatar_link": "https://avatars.steamstatic.com/dbaf3958fffebf266ce5c04316da744987e9b1fb_full.jpg",
4358 "steam_id": "76561199221334063",
4359 "sp_score": 99,
4360 "mp_score": 61,
4361 "overall_score": 160,
4362 "sp_rank": 23,
4363 "mp_rank": 20,
4364 "overall_rank": 23
4365 },
4366 {
4367 "user_name": "Daddy Sparky420",
4368 "avatar_link": "https://avatars.steamstatic.com/14bd5c9bee517058bed74638465e5f68f8ce1d68_full.jpg",
4369 "steam_id": "76561198044110926",
4370 "sp_score": 108,
4371 "mp_score": 52,
4372 "overall_score": 160,
4373 "sp_rank": 31,
4374 "mp_rank": 11,
4375 "overall_rank": 23
4376 },
4377 {
4378 "user_name": "Lowengeist",
4379 "avatar_link": "https://avatars.steamstatic.com/4f9a9168c48434a27dfe32d5831ce9fdcfb3ed96_full.jpg",
4380 "steam_id": "76561198122276362",
4381 "sp_score": 110,
4382 "mp_score": 51,
4383 "overall_score": 161,
4384 "sp_rank": 33,
4385 "mp_rank": 10,
4386 "overall_rank": 24
4387 },
4388 {
4389 "user_name": "fullheart2",
4390 "avatar_link": "https://avatars.steamstatic.com/1daea993c3be4435d49bc50f7b011d639a08f3c9_full.jpg",
4391 "steam_id": "76561197997838862",
4392 "sp_score": 108,
4393 "mp_score": 53,
4394 "overall_score": 161,
4395 "sp_rank": 31,
4396 "mp_rank": 12,
4397 "overall_rank": 24
4398 },
4399 {
4400 "user_name": "Zypeh",
4401 "avatar_link": "https://avatars.steamstatic.com/bfd2b759e7e6300fc709857b9e6db802084544d1_full.jpg",
4402 "steam_id": "76561198039230536",
4403 "sp_score": 106,
4404 "mp_score": 55,
4405 "overall_score": 161,
4406 "sp_rank": 29,
4407 "mp_rank": 14,
4408 "overall_rank": 24
4409 },
4410 {
4411 "user_name": "LsDK_",
4412 "avatar_link": "https://avatars.steamstatic.com/4bf97c27bd5824296c0dedd11f5da1b2f0cdb7a5_full.jpg",
4413 "steam_id": "76561198103821970",
4414 "sp_score": 117,
4415 "mp_score": 47,
4416 "overall_score": 164,
4417 "sp_rank": 39,
4418 "mp_rank": 6,
4419 "overall_rank": 25
4420 },
4421 {
4422 "user_name": "NeKz",
4423 "avatar_link": "https://avatars.steamstatic.com/9a86e6554aee395b3ac37d96a808335363eb79ff_full.jpg",
4424 "steam_id": "76561198049848090",
4425 "sp_score": 107,
4426 "mp_score": 57,
4427 "overall_score": 164,
4428 "sp_rank": 30,
4429 "mp_rank": 16,
4430 "overall_rank": 25
4431 },
4432 {
4433 "user_name": "Burger40",
4434 "avatar_link": "https://avatars.steamstatic.com/00db94cf7b185c69936738b5a827c63d033c6479_full.jpg",
4435 "steam_id": "76561198083196477",
4436 "sp_score": 98,
4437 "mp_score": 66,
4438 "overall_score": 164,
4439 "sp_rank": 22,
4440 "mp_rank": 25,
4441 "overall_rank": 25
4442 },
4443 {
4444 "user_name": "Fridge",
4445 "avatar_link": "https://avatars.steamstatic.com/ba9584900b25936d72bd8b7fb028eea0b0d0fa56_full.jpg",
4446 "steam_id": "76561198367132611",
4447 "sp_score": 115,
4448 "mp_score": 51,
4449 "overall_score": 166,
4450 "sp_rank": 38,
4451 "mp_rank": 10,
4452 "overall_rank": 26
4453 },
4454 {
4455 "user_name": "Jarool",
4456 "avatar_link": "https://avatars.steamstatic.com/61bb4ee9a8dd6cef5427f2170bb75d3162f3c8e8_full.jpg",
4457 "steam_id": "76561198021055079",
4458 "sp_score": 107,
4459 "mp_score": 59,
4460 "overall_score": 166,
4461 "sp_rank": 30,
4462 "mp_rank": 18,
4463 "overall_rank": 26
4464 },
4465 {
4466 "user_name": "Pr0tal",
4467 "avatar_link": "https://avatars.steamstatic.com/ce72799aa2cf4b591df09b3afc715b2259963af7_full.jpg",
4468 "steam_id": "76561198292863694",
4469 "sp_score": 98,
4470 "mp_score": 68,
4471 "overall_score": 166,
4472 "sp_rank": 22,
4473 "mp_rank": 27,
4474 "overall_rank": 26
4475 },
4476 {
4477 "user_name": "timurkazz",
4478 "avatar_link": "https://avatars.steamstatic.com/13f6adfa0189055299b1ed69418eec8dd3b5d9eb_full.jpg",
4479 "steam_id": "76561199106449775",
4480 "sp_score": 115,
4481 "mp_score": 53,
4482 "overall_score": 168,
4483 "sp_rank": 38,
4484 "mp_rank": 12,
4485 "overall_rank": 27
4486 },
4487 {
4488 "user_name": "Morality",
4489 "avatar_link": "https://avatars.steamstatic.com/2ea3e5885aa789acfc3640788905a414c408edc9_full.jpg",
4490 "steam_id": "76561198799058701",
4491 "sp_score": 115,
4492 "mp_score": 53,
4493 "overall_score": 168,
4494 "sp_rank": 38,
4495 "mp_rank": 12,
4496 "overall_rank": 27
4497 },
4498 {
4499 "user_name": "Jess3n",
4500 "avatar_link": "https://avatars.steamstatic.com/1ee47a4ad1a50a4307cde6a9c543b3207942596c_full.jpg",
4501 "steam_id": "76561198870020820",
4502 "sp_score": 112,
4503 "mp_score": 58,
4504 "overall_score": 170,
4505 "sp_rank": 35,
4506 "mp_rank": 17,
4507 "overall_rank": 28
4508 },
4509 {
4510 "user_name": "Leve",
4511 "avatar_link": "https://avatars.steamstatic.com/7a56621890546d1a54d4b583198b4d30411950b2_full.jpg",
4512 "steam_id": "76561198902321340",
4513 "sp_score": 111,
4514 "mp_score": 60,
4515 "overall_score": 171,
4516 "sp_rank": 34,
4517 "mp_rank": 19,
4518 "overall_rank": 29
4519 },
4520 {
4521 "user_name": "Imagine a cool name",
4522 "avatar_link": "https://avatars.steamstatic.com/ed6186b9c575f4df60c138785c9c004ad9bd4fae_full.jpg",
4523 "steam_id": "76561198869299905",
4524 "sp_score": 101,
4525 "mp_score": 71,
4526 "overall_score": 172,
4527 "sp_rank": 25,
4528 "mp_rank": 30,
4529 "overall_rank": 30
4530 },
4531 {
4532 "user_name": "nintendude",
4533 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
4534 "steam_id": "76561198307085542",
4535 "sp_score": 118,
4536 "mp_score": 54,
4537 "overall_score": 172,
4538 "sp_rank": 40,
4539 "mp_rank": 13,
4540 "overall_rank": 30
4541 },
4542 {
4543 "user_name": "Shiro",
4544 "avatar_link": "https://avatars.steamstatic.com/7160e03d7c638627813e5fb993bf921c828b02c2_full.jpg",
4545 "steam_id": "76561198118924124",
4546 "sp_score": 119,
4547 "mp_score": 55,
4548 "overall_score": 174,
4549 "sp_rank": 41,
4550 "mp_rank": 14,
4551 "overall_rank": 31
4552 },
4553 {
4554 "user_name": "stip",
4555 "avatar_link": "https://avatars.steamstatic.com/19be8fd7d791a14920566ce35cc2798ecda8a9e4_full.jpg",
4556 "steam_id": "76561198238515424",
4557 "sp_score": 113,
4558 "mp_score": 63,
4559 "overall_score": 176,
4560 "sp_rank": 36,
4561 "mp_rank": 22,
4562 "overall_rank": 32
4563 },
4564 {
4565 "user_name": "Snow",
4566 "avatar_link": "https://avatars.steamstatic.com/64b513f2c1f8a490670aa3d004d71b95207035b8_full.jpg",
4567 "steam_id": "76561198842803939",
4568 "sp_score": 121,
4569 "mp_score": 56,
4570 "overall_score": 177,
4571 "sp_rank": 42,
4572 "mp_rank": 15,
4573 "overall_rank": 33
4574 },
4575 {
4576 "user_name": "h@iku",
4577 "avatar_link": "https://avatars.steamstatic.com/bfb0f0be647a28135ba306cd2e40c6ece3ca11b2_full.jpg",
4578 "steam_id": "76561198343098423",
4579 "sp_score": 123,
4580 "mp_score": 55,
4581 "overall_score": 178,
4582 "sp_rank": 43,
4583 "mp_rank": 14,
4584 "overall_rank": 34
4585 },
4586 {
4587 "user_name": "AMJ",
4588 "avatar_link": "https://avatars.steamstatic.com/43480cfa66f1b35c2098016221a4dc19ed4fab55_full.jpg",
4589 "steam_id": "76561198067936604",
4590 "sp_score": 121,
4591 "mp_score": 57,
4592 "overall_score": 178,
4593 "sp_rank": 42,
4594 "mp_rank": 16,
4595 "overall_rank": 34
4596 },
4597 {
4598 "user_name": "Chevalix",
4599 "avatar_link": "https://avatars.steamstatic.com/db8a0073f499823d0fb4ba89ee8716971a321a4e_full.jpg",
4600 "steam_id": "76561198302681368",
4601 "sp_score": 121,
4602 "mp_score": 58,
4603 "overall_score": 179,
4604 "sp_rank": 42,
4605 "mp_rank": 17,
4606 "overall_rank": 35
4607 },
4608 {
4609 "user_name": "Yugge",
4610 "avatar_link": "https://avatars.steamstatic.com/dc7c081330432a22b2d44cca2c02285c3ad04813_full.jpg",
4611 "steam_id": "76561198405615224",
4612 "sp_score": 117,
4613 "mp_score": 63,
4614 "overall_score": 180,
4615 "sp_rank": 39,
4616 "mp_rank": 22,
4617 "overall_rank": 36
4618 },
4619 {
4620 "user_name": "Kitsune",
4621 "avatar_link": "https://avatars.steamstatic.com/20bd0d2ff33f74c95500c5d11d4b550aa04fe505_full.jpg",
4622 "steam_id": "76561198136477838",
4623 "sp_score": 136,
4624 "mp_score": 48,
4625 "overall_score": 184,
4626 "sp_rank": 56,
4627 "mp_rank": 7,
4628 "overall_rank": 37
4629 },
4630 {
4631 "user_name": "ุ",
4632 "avatar_link": "https://avatars.steamstatic.com/b698f81978cd408b5e210f5b5c09d308ae75165b_full.jpg",
4633 "steam_id": "76561198200883819",
4634 "sp_score": 121,
4635 "mp_score": 64,
4636 "overall_score": 185,
4637 "sp_rank": 42,
4638 "mp_rank": 23,
4639 "overall_rank": 38
4640 },
4641 {
4642 "user_name": "UrMomPlebLol",
4643 "avatar_link": "https://avatars.steamstatic.com/5b5b9357badc3d9e9ba53d52cf851a85df4a910c_full.jpg",
4644 "steam_id": "76561198371482646",
4645 "sp_score": 112,
4646 "mp_score": 73,
4647 "overall_score": 185,
4648 "sp_rank": 35,
4649 "mp_rank": 32,
4650 "overall_rank": 38
4651 },
4652 {
4653 "user_name": "100kitaizzev",
4654 "avatar_link": "https://avatars.steamstatic.com/93c7cb31e2b51e636e308788c7264b70e9756c9d_full.jpg",
4655 "steam_id": "76561198006939388",
4656 "sp_score": 123,
4657 "mp_score": 65,
4658 "overall_score": 188,
4659 "sp_rank": 43,
4660 "mp_rank": 24,
4661 "overall_rank": 39
4662 },
4663 {
4664 "user_name": "ThatGoatWhoIsEpic",
4665 "avatar_link": "https://avatars.steamstatic.com/5049e37e3b511134a4a1b8359a8103348c09ff17_full.jpg",
4666 "steam_id": "76561198074525881",
4667 "sp_score": 117,
4668 "mp_score": 72,
4669 "overall_score": 189,
4670 "sp_rank": 39,
4671 "mp_rank": 31,
4672 "overall_rank": 40
4673 },
4674 {
4675 "user_name": "Soulfur",
4676 "avatar_link": "https://avatars.steamstatic.com/af59571446fe62756d619b9e42a82c432390ccf0_full.jpg",
4677 "steam_id": "76561198181126266",
4678 "sp_score": 135,
4679 "mp_score": 56,
4680 "overall_score": 191,
4681 "sp_rank": 55,
4682 "mp_rank": 15,
4683 "overall_rank": 41
4684 },
4685 {
4686 "user_name": "Throw",
4687 "avatar_link": "https://avatars.steamstatic.com/2c01a87d1b0789f7bdd1f3e693ef9987e49abe01_full.jpg",
4688 "steam_id": "76561198952505877",
4689 "sp_score": 115,
4690 "mp_score": 78,
4691 "overall_score": 193,
4692 "sp_rank": 38,
4693 "mp_rank": 36,
4694 "overall_rank": 42
4695 },
4696 {
4697 "user_name": "Myhr",
4698 "avatar_link": "https://avatars.steamstatic.com/deec440da6c13c8fa72f003d8396c15d6238c89e_full.jpg",
4699 "steam_id": "76561198054566481",
4700 "sp_score": 141,
4701 "mp_score": 52,
4702 "overall_score": 193,
4703 "sp_rank": 61,
4704 "mp_rank": 11,
4705 "overall_rank": 42
4706 },
4707 {
4708 "user_name": "Fyrestorm",
4709 "avatar_link": "https://avatars.steamstatic.com/c0c82fa70c986348caaaea71f3ccac1b13c0c4eb_full.jpg",
4710 "steam_id": "76561198035761863",
4711 "sp_score": 142,
4712 "mp_score": 55,
4713 "overall_score": 197,
4714 "sp_rank": 62,
4715 "mp_rank": 14,
4716 "overall_rank": 43
4717 },
4718 {
4719 "user_name": "Turmoil",
4720 "avatar_link": "https://avatars.steamstatic.com/ceeb79bfd441b1928af34195dfde660b44f002dd_full.jpg",
4721 "steam_id": "76561197997770103",
4722 "sp_score": 142,
4723 "mp_score": 57,
4724 "overall_score": 199,
4725 "sp_rank": 62,
4726 "mp_rank": 16,
4727 "overall_rank": 44
4728 },
4729 {
4730 "user_name": "Tenacite the MAD Milshake",
4731 "avatar_link": "https://avatars.steamstatic.com/dc22cc282f8bd43f3efde936b7263130f09358b8_full.jpg",
4732 "steam_id": "76561198389681125",
4733 "sp_score": 152,
4734 "mp_score": 49,
4735 "overall_score": 201,
4736 "sp_rank": 69,
4737 "mp_rank": 8,
4738 "overall_rank": 45
4739 },
4740 {
4741 "user_name": "Blenderiste09",
4742 "avatar_link": "https://avatars.steamstatic.com/79d3fe5839617eb83a9661071ed021dd56ac8a5b_full.jpg",
4743 "steam_id": "76561198251755710",
4744 "sp_score": 145,
4745 "mp_score": 56,
4746 "overall_score": 201,
4747 "sp_rank": 65,
4748 "mp_rank": 15,
4749 "overall_rank": 45
4750 },
4751 {
4752 "user_name": "laredeshot",
4753 "avatar_link": "https://avatars.steamstatic.com/8ffb58e0cddad5293c48250deb458f428b9f6736_full.jpg",
4754 "steam_id": "76561198261656551",
4755 "sp_score": 149,
4756 "mp_score": 56,
4757 "overall_score": 205,
4758 "sp_rank": 67,
4759 "mp_rank": 15,
4760 "overall_rank": 46
4761 },
4762 {
4763 "user_name": "savvydruid",
4764 "avatar_link": "https://avatars.steamstatic.com/687d290c9238b42a790216892cc21f718741bd83_full.jpg",
4765 "steam_id": "76561199013726692",
4766 "sp_score": 157,
4767 "mp_score": 53,
4768 "overall_score": 210,
4769 "sp_rank": 74,
4770 "mp_rank": 12,
4771 "overall_rank": 47
4772 },
4773 {
4774 "user_name": "Schwi",
4775 "avatar_link": "https://avatars.steamstatic.com/a5ab762db09205fc49a6fa8fd1d09daafc3ac6e4_full.jpg",
4776 "steam_id": "76561198384377251",
4777 "sp_score": 147,
4778 "mp_score": 69,
4779 "overall_score": 216,
4780 "sp_rank": 66,
4781 "mp_rank": 28,
4782 "overall_rank": 48
4783 },
4784 {
4785 "user_name": "1 Portal SWAG",
4786 "avatar_link": "https://avatars.steamstatic.com/8766c163ce9fd7a584c5347dab0a6a49766102e8_full.jpg",
4787 "steam_id": "76561198253811824",
4788 "sp_score": 137,
4789 "mp_score": 82,
4790 "overall_score": 219,
4791 "sp_rank": 57,
4792 "mp_rank": 39,
4793 "overall_rank": 49
4794 },
4795 {
4796 "user_name": "Lathil",
4797 "avatar_link": "https://avatars.steamstatic.com/6636331f0f7d69a2ef6557a124ae4a3389466047_full.jpg",
4798 "steam_id": "76561198404861950",
4799 "sp_score": 165,
4800 "mp_score": 59,
4801 "overall_score": 224,
4802 "sp_rank": 79,
4803 "mp_rank": 18,
4804 "overall_rank": 50
4805 },
4806 {
4807 "user_name": "badger",
4808 "avatar_link": "https://avatars.steamstatic.com/cbea4cfe87dab41ed9d2b53be876110b98e4111a_full.jpg",
4809 "steam_id": "76561198861024091",
4810 "sp_score": 135,
4811 "mp_score": 89,
4812 "overall_score": 224,
4813 "sp_rank": 55,
4814 "mp_rank": 43,
4815 "overall_rank": 50
4816 },
4817 {
4818 "user_name": "MegaWaTT",
4819 "avatar_link": "https://avatars.steamstatic.com/ed56d8fc9c49a77d3f8c8bd6cc3efa72e714b54d_full.jpg",
4820 "steam_id": "76561198363863187",
4821 "sp_score": 137,
4822 "mp_score": 92,
4823 "overall_score": 229,
4824 "sp_rank": 57,
4825 "mp_rank": 45,
4826 "overall_rank": 51
4827 },
4828 {
4829 "user_name": "Spyrunite",
4830 "avatar_link": "https://avatars.steamstatic.com/184e99f06e36b81346214c37f6b448f4d71fcb8b_full.jpg",
4831 "steam_id": "76561198026851335",
4832 "sp_score": 132,
4833 "mp_score": 98,
4834 "overall_score": 230,
4835 "sp_rank": 52,
4836 "mp_rank": 50,
4837 "overall_rank": 52
4838 },
4839 {
4840 "user_name": "Saxton Hale",
4841 "avatar_link": "https://avatars.steamstatic.com/2f335962fbb8431ea3f5606fe3e1881dce47e63a_full.jpg",
4842 "steam_id": "76561197998253566",
4843 "sp_score": 155,
4844 "mp_score": 75,
4845 "overall_score": 230,
4846 "sp_rank": 72,
4847 "mp_rank": 34,
4848 "overall_rank": 52
4849 },
4850 {
4851 "user_name": "XTLmaker",
4852 "avatar_link": "https://avatars.steamstatic.com/b3c041f3eb316e0edf16e6ba36f426b433e16cee_full.jpg",
4853 "steam_id": "76561199032030834",
4854 "sp_score": 134,
4855 "mp_score": 97,
4856 "overall_score": 231,
4857 "sp_rank": 54,
4858 "mp_rank": 49,
4859 "overall_rank": 53
4860 },
4861 {
4862 "user_name": "wol",
4863 "avatar_link": "https://avatars.steamstatic.com/689a4b1be66db3f28a1567c7b1bb7e8e2d1e1d90_full.jpg",
4864 "steam_id": "76561199007976762",
4865 "sp_score": 177,
4866 "mp_score": 57,
4867 "overall_score": 234,
4868 "sp_rank": 84,
4869 "mp_rank": 16,
4870 "overall_rank": 54
4871 },
4872 {
4873 "user_name": "SilentiumGradas",
4874 "avatar_link": "https://avatars.steamstatic.com/b26b46bc2dd6efece8b6cbcff8ba263801b5b6dc_full.jpg",
4875 "steam_id": "76561199006050430",
4876 "sp_score": 142,
4877 "mp_score": 101,
4878 "overall_score": 243,
4879 "sp_rank": 62,
4880 "mp_rank": 51,
4881 "overall_rank": 55
4882 },
4883 {
4884 "user_name": "ki4rakaM [RUS]",
4885 "avatar_link": "https://avatars.steamstatic.com/cae7d5a1e4b04f70dc0c1599d932edb423e65870_full.jpg",
4886 "steam_id": "76561198227911092",
4887 "sp_score": 157,
4888 "mp_score": 89,
4889 "overall_score": 246,
4890 "sp_rank": 74,
4891 "mp_rank": 43,
4892 "overall_rank": 56
4893 },
4894 {
4895 "user_name": "Imanex",
4896 "avatar_link": "https://avatars.steamstatic.com/82d1ac52aeddb7f08eb0f85d4f7d96160af30bb9_full.jpg",
4897 "steam_id": "76561197974616889",
4898 "sp_score": 169,
4899 "mp_score": 82,
4900 "overall_score": 251,
4901 "sp_rank": 81,
4902 "mp_rank": 39,
4903 "overall_rank": 57
4904 },
4905 {
4906 "user_name": "Betsruner",
4907 "avatar_link": "https://avatars.steamstatic.com/6e5b5f43361149652d556073c34a4c3bd5c56df2_full.jpg",
4908 "steam_id": "76561198048179892",
4909 "sp_score": 153,
4910 "mp_score": 113,
4911 "overall_score": 266,
4912 "sp_rank": 70,
4913 "mp_rank": 57,
4914 "overall_rank": 58
4915 },
4916 {
4917 "user_name": "Schlepian",
4918 "avatar_link": "https://avatars.steamstatic.com/f7be9949784d7864c619a72e0bec1138a14933ff_full.jpg",
4919 "steam_id": "76561198021734854",
4920 "sp_score": 161,
4921 "mp_score": 105,
4922 "overall_score": 266,
4923 "sp_rank": 76,
4924 "mp_rank": 52,
4925 "overall_rank": 58
4926 },
4927 {
4928 "user_name": "Schlay",
4929 "avatar_link": "https://avatars.steamstatic.com/1c81f34080417cab9a836c003e5c319229e528f9_full.jpg",
4930 "steam_id": "76561198042995537",
4931 "sp_score": 170,
4932 "mp_score": 108,
4933 "overall_score": 278,
4934 "sp_rank": 82,
4935 "mp_rank": 53,
4936 "overall_rank": 59
4937 },
4938 {
4939 "user_name": "¯\\_(ツ)_/¯",
4940 "avatar_link": "https://avatars.steamstatic.com/fb9c36c36e54b8ca5f2e1cbd89c06574d1348af0_full.jpg",
4941 "steam_id": "76561198001523094",
4942 "sp_score": 175,
4943 "mp_score": 127,
4944 "overall_score": 302,
4945 "sp_rank": 83,
4946 "mp_rank": 64,
4947 "overall_rank": 60
4948 },
4949 {
4950 "user_name": "lampishboi",
4951 "avatar_link": "https://avatars.steamstatic.com/22bc948278437707cf69cc70a153f8363c95bccf_full.jpg",
4952 "steam_id": "76561198994808916",
4953 "sp_score": 131,
4954 "mp_score": 199,
4955 "overall_score": 330,
4956 "sp_rank": 51,
4957 "mp_rank": 81,
4958 "overall_rank": 61
4959 },
4960 {
4961 "user_name": "『 Jonese1234 』",
4962 "avatar_link": "https://avatars.steamstatic.com/9f6de098624a8f81ba6d2318e1923bdda1c710d6_full.jpg",
4963 "steam_id": "76561198045074889",
4964 "sp_score": 157,
4965 "mp_score": 206,
4966 "overall_score": 363,
4967 "sp_rank": 74,
4968 "mp_rank": 85,
4969 "overall_rank": 62
4970 },
4971 {
4972 "user_name": "Potatoes",
4973 "avatar_link": "https://avatars.steamstatic.com/94821c98d19e5eda6ec315289aa28b191084f301_full.jpg",
4974 "steam_id": "76561197974561284",
4975 "sp_score": 248,
4976 "mp_score": 209,
4977 "overall_score": 457,
4978 "sp_rank": 89,
4979 "mp_rank": 88,
4980 "overall_rank": 63
4981 }
4982 ]
4983 }
4984}
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index e4bde75..bdd3adc 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import { Routes, Route } from "react-router-dom"; 2import { Routes, Route } from "react-router-dom";
3import { Helmet } from "react-helmet";
3 4
4import { UserProfile } from '@customTypes/Profile'; 5import { UserProfile } from '@customTypes/Profile';
5import Sidebar from './components/Sidebar'; 6import Sidebar from './components/Sidebar';
@@ -66,14 +67,12 @@ const App: React.FC = () => {
66 _fetch_games(); 67 _fetch_games();
67 }, []); 68 }, []);
68 69
69 if (!games) {
70 return (
71 <></>
72 )
73 };
74
75 return ( 70 return (
76 <> 71 <>
72 <Helmet>
73 <title>LPHUB</title>
74 <meta name="description" content="Least Portals Hub" />
75 </Helmet>
77 <UploadRunDialog token={token} open={uploadRunDialog} onClose={(updateProfile) => { 76 <UploadRunDialog token={token} open={uploadRunDialog} onClose={(updateProfile) => {
78 setUploadRunDialog(false); 77 setUploadRunDialog(false);
79 if (updateProfile) { 78 if (updateProfile) {
diff --git a/frontend/src/api/Api.ts b/frontend/src/api/Api.ts
index 2e55ab4..862e688 100644
--- a/frontend/src/api/Api.ts
+++ b/frontend/src/api/Api.ts
@@ -29,13 +29,13 @@ export const API = {
29 get_unofficial_rankings: () => get_unofficial_rankings(), 29 get_unofficial_rankings: () => get_unofficial_rankings(),
30 // Maps 30 // Maps
31 get_map_summary: (map_id: string) => get_map_summary(map_id), 31 get_map_summary: (map_id: string) => get_map_summary(map_id),
32 get_map_leaderboard: (map_id: string) => get_map_leaderboard(map_id), 32 get_map_leaderboard: (map_id: string, page: string) => get_map_leaderboard(map_id, page),
33 get_map_discussions: (map_id: string) => get_map_discussions(map_id), 33 get_map_discussions: (map_id: string) => get_map_discussions(map_id),
34 get_map_discussion: (map_id: string, discussion_id: number) => get_map_discussion(map_id, discussion_id), 34 get_map_discussion: (map_id: string, discussion_id: number) => get_map_discussion(map_id, discussion_id),
35 35
36 post_map_discussion: (token: string, map_id: string, content: MapDiscussionContent) => post_map_discussion(token, map_id, content), 36 post_map_discussion: (token: string, map_id: string, content: MapDiscussionContent) => post_map_discussion(token, map_id, content),
37 post_map_discussion_comment: (token: string, map_id: string, discussion_id: number, comment: string) => post_map_discussion_comment(token, map_id, discussion_id, comment), 37 post_map_discussion_comment: (token: string, map_id: string, discussion_id: number, comment: string) => post_map_discussion_comment(token, map_id, discussion_id, comment),
38 post_record: (token: string, run: UploadRunContent) => post_record(token, run), 38 post_record: (token: string, run: UploadRunContent, map_id: number) => post_record(token, run, map_id),
39 39
40 delete_map_discussion: (token: string, map_id: string, discussion_id: number) => delete_map_discussion(token, map_id, discussion_id), 40 delete_map_discussion: (token: string, map_id: string, discussion_id: number) => delete_map_discussion(token, map_id, discussion_id),
41 41
diff --git a/frontend/src/api/Maps.ts b/frontend/src/api/Maps.ts
index 89657b5..aa967ce 100644
--- a/frontend/src/api/Maps.ts
+++ b/frontend/src/api/Maps.ts
@@ -8,8 +8,8 @@ export const get_map_summary = async (map_id: string): Promise<MapSummary> => {
8 return response.data.data; 8 return response.data.data;
9}; 9};
10 10
11export const get_map_leaderboard = async (map_id: string): Promise<MapLeaderboard | undefined> => { 11export const get_map_leaderboard = async (map_id: string, page: string): Promise<MapLeaderboard | undefined> => {
12 const response = await axios.get(url(`maps/${map_id}/leaderboards`)); 12 const response = await axios.get(url(`maps/${map_id}/leaderboards?page=${page}`));
13 if (!response.data.success) { 13 if (!response.data.success) {
14 return undefined; 14 return undefined;
15 } 15 }
@@ -73,9 +73,9 @@ export const delete_map_discussion = async (token: string, map_id: string, discu
73 return response.data.success; 73 return response.data.success;
74}; 74};
75 75
76export const post_record = async (token: string, run: UploadRunContent): Promise<[boolean, string]> => { 76export const post_record = async (token: string, run: UploadRunContent, map_id: number): Promise<[boolean, string]> => {
77 if (run.partner_demo) { 77 if (run.partner_demo) {
78 const response = await axios.postForm(url(`maps/${run.map_id}/record`), { 78 const response = await axios.postForm(url(`maps/${map_id}/record`), {
79 "host_demo": run.host_demo, 79 "host_demo": run.host_demo,
80 "partner_demo": run.partner_demo, 80 "partner_demo": run.partner_demo,
81 }, { 81 }, {
@@ -83,16 +83,16 @@ export const post_record = async (token: string, run: UploadRunContent): Promise
83 "Authorization": token, 83 "Authorization": token,
84 } 84 }
85 }); 85 });
86 return [ response.data.success, response.data.message ]; 86 return [response.data.success, response.data.message];
87 } else { 87 } else {
88 const response = await axios.postForm(url(`maps/${run.map_id}/record`), { 88 const response = await axios.postForm(url(`maps/${map_id}/record`), {
89 "host_demo": run.host_demo, 89 "host_demo": run.host_demo,
90 }, { 90 }, {
91 headers: { 91 headers: {
92 "Authorization": token, 92 "Authorization": token,
93 } 93 }
94 }); 94 });
95 return [ response.data.success, response.data.message ]; 95 return [response.data.success, response.data.message];
96 } 96 }
97} 97}
98 98
diff --git a/frontend/src/components/Leaderboards.tsx b/frontend/src/components/Leaderboards.tsx
index 4a8b463..fb614fa 100644
--- a/frontend/src/components/Leaderboards.tsx
+++ b/frontend/src/components/Leaderboards.tsx
@@ -1,20 +1,33 @@
1import React from 'react'; 1import React from 'react';
2import { Link } from 'react-router-dom'; 2import { Link, useNavigate } from 'react-router-dom';
3 3
4import { DownloadIcon, ThreedotIcon } from '@images/Images'; 4import { DownloadIcon, ThreedotIcon } from '@images/Images';
5import { MapLeaderboard } from '@customTypes/Map'; 5import { MapLeaderboard } from '@customTypes/Map';
6import { ticks_to_time, time_ago } from '@utils/Time'; 6import { ticks_to_time, time_ago } from '@utils/Time';
7import { API } from "@api/Api";
7import useMessage from "@hooks/UseMessage"; 8import useMessage from "@hooks/UseMessage";
8import "@css/Maps.css" 9import "@css/Maps.css"
9 10
10interface LeaderboardsProps { 11interface LeaderboardsProps {
11 data?: MapLeaderboard; 12 mapID: string;
12} 13}
13 14
14const Leaderboards: React.FC<LeaderboardsProps> = ({ data }) => { 15const Leaderboards: React.FC<LeaderboardsProps> = ({ mapID }) => {
16 const navigate = useNavigate();
17 const [data, setData] = React.useState<MapLeaderboard | undefined>(undefined);
18 const [pageNumber, setPageNumber] = React.useState<number>(1);
19
20 const _fetch_map_leaderboards = async () => {
21 const mapLeaderboards = await API.get_map_leaderboard(mapID, pageNumber.toString());
22 setData(mapLeaderboards);
23 };
15 24
16 const { message, MessageDialogComponent } = useMessage(); 25 const { message, MessageDialogComponent } = useMessage();
17 const [pageNumber, setPageNumber] = React.useState<number>(1); 26
27 React.useEffect(() => {
28 _fetch_map_leaderboards();
29 console.log(data);
30 }, [pageNumber, navigate])
18 31
19 if (!data) { 32 if (!data) {
20 return ( 33 return (
diff --git a/frontend/src/components/Summary.tsx b/frontend/src/components/Summary.tsx
index 4bcaa6a..7da2f1e 100644
--- a/frontend/src/components/Summary.tsx
+++ b/frontend/src/components/Summary.tsx
@@ -140,20 +140,34 @@ const Summary: React.FC<SummaryProps> = ({ selectedRun, setSelectedRun, data })
140 <section id='section4' className='summary1'> 140 <section id='section4' className='summary1'>
141 <div id='difficulty'> 141 <div id='difficulty'>
142 <span>Difficulty</span> 142 <span>Difficulty</span>
143 {data.summary.routes[selectedRun].rating === 0 && (<span>N/A</span>)} 143 {data.map.difficulty <= 2 && (<span style={{ color: "lime" }}>Very easy</span>)}
144 {data.summary.routes[selectedRun].rating === 1 && (<span style={{ color: "lime" }}>Very easy</span>)} 144 {data.map.difficulty > 2 && data.map.difficulty <= 4 && (<span style={{ color: "green" }}>Easy</span>)}
145 {data.summary.routes[selectedRun].rating === 2 && (<span style={{ color: "green" }}>Easy</span>)} 145 {data.map.difficulty > 4 && data.map.difficulty <= 6 && (<span style={{ color: "yellow" }}>Medium</span>)}
146 {data.summary.routes[selectedRun].rating === 3 && (<span style={{ color: "yellow" }}>Medium</span>)} 146 {data.map.difficulty > 6 && data.map.difficulty <= 8 && (<span style={{ color: "orange" }}>Hard</span>)}
147 {data.summary.routes[selectedRun].rating === 4 && (<span style={{ color: "orange" }}>Hard</span>)} 147 {data.map.difficulty > 8 && data.map.difficulty <= 10 && (<span style={{ color: "red" }}>Very hard</span>)}
148 {data.summary.routes[selectedRun].rating === 5 && (<span style={{ color: "red" }}>Very hard</span>)}
149 <div> 148 <div>
150 {data.summary.routes[selectedRun].rating === 1 ? (<div className='difficulty-rating' style={{ backgroundColor: "lime" }}></div>) : (<div className='difficulty-rating'></div>)} 149 {data.map.difficulty <= 2 ? (<div className='difficulty-rating' style={{ backgroundColor: "lime" }}></div>) : (<div className='difficulty-rating'></div>)}
151 {data.summary.routes[selectedRun].rating === 2 ? (<div className='difficulty-rating' style={{ backgroundColor: "green" }}></div>) : (<div className='difficulty-rating'></div>)} 150 {data.map.difficulty > 2 && data.map.difficulty <= 4 ? (<div className='difficulty-rating' style={{ backgroundColor: "green" }}></div>) : (<div className='difficulty-rating'></div>)}
152 {data.summary.routes[selectedRun].rating === 3 ? (<div className='difficulty-rating' style={{ backgroundColor: "yellow" }}></div>) : (<div className='difficulty-rating'></div>)} 151 {data.map.difficulty > 4 && data.map.difficulty <= 6 ? (<div className='difficulty-rating' style={{ backgroundColor: "yellow" }}></div>) : (<div className='difficulty-rating'></div>)}
153 {data.summary.routes[selectedRun].rating === 4 ? (<div className='difficulty-rating' style={{ backgroundColor: "orange" }}></div>) : (<div className='difficulty-rating'></div>)} 152 {data.map.difficulty > 6 && data.map.difficulty <= 8 ? (<div className='difficulty-rating' style={{ backgroundColor: "orange" }}></div>) : (<div className='difficulty-rating'></div>)}
154 {data.summary.routes[selectedRun].rating === 5 ? (<div className='difficulty-rating' style={{ backgroundColor: "red" }}></div>) : (<div className='difficulty-rating'></div>)} 153 {data.map.difficulty > 8 && data.map.difficulty <= 10 ? (<div className='difficulty-rating' style={{ backgroundColor: "red" }}></div>) : (<div className='difficulty-rating'></div>)}
155 </div> 154 </div>
156 </div> 155 </div>
156 {/* <div id='difficulty'>
157 <span>Difficulty</span>
158 {data.summary.routes[selectedRun].rating <= 2 && (<span style={{ color: "lime" }}>Very easy</span>)}
159 {data.summary.routes[selectedRun].rating > 2 && data.summary.routes[selectedRun].rating <= 4 && (<span style={{ color: "green" }}>Easy</span>)}
160 {data.summary.routes[selectedRun].rating > 4 && data.summary.routes[selectedRun].rating <= 6 && (<span style={{ color: "yellow" }}>Medium</span>)}
161 {data.summary.routes[selectedRun].rating > 6 && data.summary.routes[selectedRun].rating <= 8 && (<span style={{ color: "orange" }}>Hard</span>)}
162 {data.summary.routes[selectedRun].rating > 8 && data.summary.routes[selectedRun].rating <= 10 && (<span style={{ color: "red" }}>Very hard</span>)}
163 <div>
164 {data.summary.routes[selectedRun].rating <= 2 ? (<div className='difficulty-rating' style={{ backgroundColor: "lime" }}></div>) : (<div className='difficulty-rating'></div>)}
165 {data.summary.routes[selectedRun].rating > 2 && data.summary.routes[selectedRun].rating <= 4 ? (<div className='difficulty-rating' style={{ backgroundColor: "green" }}></div>) : (<div className='difficulty-rating'></div>)}
166 {data.summary.routes[selectedRun].rating > 4 && data.summary.routes[selectedRun].rating <= 6 ? (<div className='difficulty-rating' style={{ backgroundColor: "yellow" }}></div>) : (<div className='difficulty-rating'></div>)}
167 {data.summary.routes[selectedRun].rating > 6 && data.summary.routes[selectedRun].rating <= 8 ? (<div className='difficulty-rating' style={{ backgroundColor: "orange" }}></div>) : (<div className='difficulty-rating'></div>)}
168 {data.summary.routes[selectedRun].rating > 8 && data.summary.routes[selectedRun].rating <= 10 ? (<div className='difficulty-rating' style={{ backgroundColor: "red" }}></div>) : (<div className='difficulty-rating'></div>)}
169 </div>
170 </div> */}
157 <div id='count'> 171 <div id='count'>
158 <span>Completion Count</span> 172 <span>Completion Count</span>
159 <div>{data.summary.routes[selectedRun].completion_count}</div> 173 <div>{data.summary.routes[selectedRun].completion_count}</div>
diff --git a/frontend/src/components/UploadRunDialog.tsx b/frontend/src/components/UploadRunDialog.tsx
index 951944b..971a747 100644
--- a/frontend/src/components/UploadRunDialog.tsx
+++ b/frontend/src/components/UploadRunDialog.tsx
@@ -5,12 +5,12 @@ import { ScoreboardTempUpdate, SourceDemoParser, NetMessages } from '@nekz/sdp';
5import btn from "@css/Button.module.css"; 5import btn from "@css/Button.module.css";
6import '@css/UploadRunDialog.css'; 6import '@css/UploadRunDialog.css';
7import { Game } from '@customTypes/Game'; 7import { Game } from '@customTypes/Game';
8import { Map } from '@customTypes/Map';
9import { API } from '@api/Api'; 8import { API } from '@api/Api';
10import { useNavigate } from 'react-router-dom'; 9import { useNavigate } from 'react-router-dom';
11import useMessage from '@hooks/UseMessage'; 10import useMessage from '@hooks/UseMessage';
12import useConfirm from '@hooks/UseConfirm'; 11import useConfirm from '@hooks/UseConfirm';
13import useMessageLoad from "@hooks/UseMessageLoad"; 12import useMessageLoad from "@hooks/UseMessageLoad";
13import { MapNames } from '@customTypes/MapNames';
14 14
15interface UploadRunDialogProps { 15interface UploadRunDialogProps {
16 token?: string; 16 token?: string;
@@ -28,19 +28,11 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
28 const navigate = useNavigate(); 28 const navigate = useNavigate();
29 29
30 const [uploadRunContent, setUploadRunContent] = React.useState<UploadRunContent>({ 30 const [uploadRunContent, setUploadRunContent] = React.useState<UploadRunContent>({
31 map_id: 0,
32 host_demo: null, 31 host_demo: null,
33 partner_demo: null, 32 partner_demo: null,
34 }); 33 });
35 34
36 const [currentMap, setCurrentMap] = React.useState<string>("");
37
38 const _set_current_map = (game_name: string) => {
39 setCurrentMap(game_name);
40 }
41
42 const [selectedGameID, setSelectedGameID] = React.useState<number>(0); 35 const [selectedGameID, setSelectedGameID] = React.useState<number>(0);
43 const [selectedGameMaps, setSelectedGameMaps] = React.useState<Map[]>([]);
44 const [selectedGameName, setSelectedGameName] = React.useState<string>(""); 36 const [selectedGameName, setSelectedGameName] = React.useState<string>("");
45 37
46 // dropdowns 38 // dropdowns
@@ -51,6 +43,7 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
51 43
52 const [dragHightlight, setDragHighlight] = React.useState<boolean>(false); 44 const [dragHightlight, setDragHighlight] = React.useState<boolean>(false);
53 const [dragHightlightPartner, setDragHighlightPartner] = React.useState<boolean>(false); 45 const [dragHightlightPartner, setDragHighlightPartner] = React.useState<boolean>(false);
46
54 const fileInputRef = React.useRef<HTMLInputElement>(null); 47 const fileInputRef = React.useRef<HTMLInputElement>(null);
55 const fileInputRefPartner = React.useRef<HTMLInputElement>(null); 48 const fileInputRefPartner = React.useRef<HTMLInputElement>(null);
56 49
@@ -103,14 +96,6 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
103 96
104 const _handle_game_select = async (game_id: string, game_name: string) => { 97 const _handle_game_select = async (game_id: string, game_name: string) => {
105 setLoading(true); 98 setLoading(true);
106 const gameMaps = await API.get_game_maps(game_id);
107 setSelectedGameMaps(gameMaps);
108 setUploadRunContent({
109 map_id: gameMaps.find((map) => !map.is_disabled)!.id, //gameMaps[0].id,
110 host_demo: null,
111 partner_demo: null,
112 });
113 _set_current_map(gameMaps.find((map) => !map.is_disabled)!.name);
114 setSelectedGameID(parseInt(game_id) - 1); 99 setSelectedGameID(parseInt(game_id) - 1);
115 setSelectedGameName(game_name); 100 setSelectedGameName(game_name);
116 setLoading(false); 101 setLoading(false);
@@ -159,6 +144,20 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
159 await message("Error", "Error while processing demo: Unable to get scoreboard result. Either there is a demo that is corrupt or haven't been recorded in challenge mode.") 144 await message("Error", "Error while processing demo: Unable to get scoreboard result. Either there is a demo that is corrupt or haven't been recorded in challenge mode.")
160 return 145 return
161 } 146 }
147
148 if (!demo.mapName || !MapNames[demo.mapName]) {
149 await message("Error", "Error while processing demo: Invalid map name.")
150 return
151 }
152
153 if (selectedGameID === 0 && MapNames[demo.mapName] > 60) {
154 await message("Error", "Error while processing demo: Invalid cooperative demo in singleplayer submission.")
155 return
156 } else if (selectedGameID === 1 && MapNames[demo.mapName] <= 60) {
157 await message("Error", "Error while processing demo: Invalid singleplayer demo in cooperative submission.")
158 return
159 }
160
162 const { portalScore, timeScore } = scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {}; 161 const { portalScore, timeScore } = scoreboard.userMessage?.as<ScoreboardTempUpdate>() ?? {};
163 162
164 const userConfirmed = await confirm("Upload Record", `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?`); 163 const userConfirmed = await confirm("Upload Record", `Map Name: ${demo.mapName}\nPortal Count: ${portalScore}\nTicks: ${timeScore}\n\nAre you sure you want to upload this demo?`);
@@ -168,10 +167,14 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
168 } 167 }
169 168
170 messageLoad("Uploading..."); 169 messageLoad("Uploading...");
171 const [success, response] = await API.post_record(token, uploadRunContent); 170 const [success, response] = await API.post_record(token, uploadRunContent, MapNames[demo.mapName]);
172 messageLoadClose(); 171 messageLoadClose();
173 await message("Upload Record", response); 172 await message("Upload Record", response);
174 if (success) { 173 if (success) {
174 setUploadRunContent({
175 host_demo: null,
176 partner_demo: null,
177 });
175 onClose(success); 178 onClose(success);
176 navigate("/profile"); 179 navigate("/profile");
177 } 180 }
@@ -180,7 +183,6 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
180 183
181 React.useEffect(() => { 184 React.useEffect(() => {
182 if (open) { 185 if (open) {
183
184 setDragHighlightPartner(false); 186 setDragHighlightPartner(false);
185 setDragHighlight(false); 187 setDragHighlight(false);
186 _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?. 188 _handle_game_select("1", "Portal 2 - Singleplayer"); // a different approach?.
@@ -204,37 +206,20 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
204 <div className='dropdown-cur'>{selectedGameName}</div> 206 <div className='dropdown-cur'>{selectedGameName}</div>
205 <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i> 207 <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i>
206 </div> 208 </div>
207 <div style={{top: "110px"}} className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}> 209 <div style={{ top: "110px" }} className={dropdown1Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}>
208 {games.map((game) => ( 210 {games.map((game) => (
209 <div onClick={() => { _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}</div> 211 <div onClick={() => { _handle_game_select(game.id.toString(), game.name); _handle_dropdowns(1) }} key={game.id}>{game.name}</div>
210 ))} 212 ))}
211 </div> 213 </div>
212 {!loading && ( 214 </div>
213 <>
214 <div style={{ padding: "25px 0px" }}>
215 <h3 style={{ margin: "0px 0px" }}>Select Map</h3>
216 <div onClick={() => _handle_dropdowns(2)} style={{ display: "flex", alignItems: "center", cursor: "pointer", justifyContent: "space-between", margin: "10px 0px" }}>
217 <span style={{ userSelect: "none" }}>{currentMap}</span>
218 <i style={{ rotate: "-90deg", transform: "translate(-5px, 10px)" }} className="triangle"></i>
219 </div>
220 </div>
221 <div style={{top: "220px"}} id='dropdown2' className={dropdown2Vis ? "upload-run-dropdown" : "upload-run-dropdown hidden"}>
222 {selectedGameMaps && selectedGameMaps.filter(gameMap => !gameMap.is_disabled).map((gameMap) => (
223 <div onClick={() => { setUploadRunContent({ ...uploadRunContent, map_id: gameMap.id }); _set_current_map(gameMap.name); _handle_dropdowns(2); }} key={gameMap.id}>{gameMap.name}</div>
224 ))}
225 </div>
226 </>
227
228 )}
229 </div>
230 215
231 { 216 {
232 !loading && 217 !loading &&
233 ( 218 (
234 <> 219 <>
235 220
236 <div> 221 <div>
237 <h3 style={{margin: "10px 0px"}}>Host Demo</h3> 222 <h3 style={{ margin: "10px 0px" }}>Host Demo</h3>
238 <div onClick={() => { _handle_file_click(true) }} onDragOver={(e) => { _handle_drag_over(e, true) }} onDrop={(e) => { _handle_drop(e, true) }} onDragLeave={(e) => { _handle_drag_leave(e, true) }} className={`upload-run-drag-area ${dragHightlight ? "upload-run-drag-area-highlight" : ""} ${uploadRunContent.host_demo ? "upload-run-drag-area-hidden" : ""}`}> 223 <div onClick={() => { _handle_file_click(true) }} onDragOver={(e) => { _handle_drag_over(e, true) }} onDrop={(e) => { _handle_drop(e, true) }} onDragLeave={(e) => { _handle_drag_leave(e, true) }} className={`upload-run-drag-area ${dragHightlight ? "upload-run-drag-area-highlight" : ""} ${uploadRunContent.host_demo ? "upload-run-drag-area-hidden" : ""}`}>
239 <input ref={fileInputRef} type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, true)} /> 224 <input ref={fileInputRef} type="file" name="host_demo" id="host_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, true)} />
240 {!uploadRunContent.host_demo ? 225 {!uploadRunContent.host_demo ?
@@ -253,38 +238,41 @@ const UploadRunDialog: React.FC<UploadRunDialogProps> = ({ token, open, onClose,
253 games[selectedGameID].is_coop && 238 games[selectedGameID].is_coop &&
254 ( 239 (
255 <> 240 <>
256 <div> 241 <div>
257 <h3 style={{margin: "10px 0px"}}>Partner Demo</h3> 242 <h3 style={{ margin: "10px 0px" }}>Partner Demo</h3>
258 <div onClick={() => { _handle_file_click(false) }} onDragOver={(e) => { _handle_drag_over(e, false) }} onDrop={(e) => { _handle_drop(e, false) }} onDragLeave={(e) => { _handle_drag_leave(e, false) }} className={`upload-run-drag-area ${dragHightlightPartner ? "upload-run-drag-area-highlight-partner" : ""} ${uploadRunContent.partner_demo ? "upload-run-drag-area-hidden" : ""}`}> 243 <div onClick={() => { _handle_file_click(false) }} onDragOver={(e) => { _handle_drag_over(e, false) }} onDrop={(e) => { _handle_drop(e, false) }} onDragLeave={(e) => { _handle_drag_leave(e, false) }} className={`upload-run-drag-area ${dragHightlightPartner ? "upload-run-drag-area-highlight-partner" : ""} ${uploadRunContent.partner_demo ? "upload-run-drag-area-hidden" : ""}`}>
259 <input ref={fileInputRefPartner} type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, false)} /> {!uploadRunContent.partner_demo ? 244 <input ref={fileInputRefPartner} type="file" name="partner_demo" id="partner_demo" accept=".dem" onChange={(e) => _handle_file_change(e.target.files, false)} /> {!uploadRunContent.partner_demo ?
260 <div>
261 <span>Drag and drop</span>
262 <div> 245 <div>
263 <span style={{ fontFamily: "BarlowSemiCondensed-Regular" }}>Or click here</span><br /> 246 <span style={{ fontFamily: "BarlowSemiCondensed-Regular" }}>Or click here</span><br />
264 <button className={btn.default}>Upload</button> 247 <button className={btn.default}>Upload</button>
265 </div> 248 </div>
266 </div> 249 : null}
267 : null}
268 250
269 <span className="upload-run-demo-name">{uploadRunContent.partner_demo?.name}</span> 251 <span className="upload-run-demo-name">{uploadRunContent.partner_demo?.name}</span>
252 </div>
270 </div> 253 </div>
271 </div>
272 </> 254 </>
273 ) 255 )
274 } 256 }
275 </div> 257 </div>
276 <div className='search-container'> 258 <div className='search-container'>
259
260 </div>
277 261
278 </div>
279
280 </> 262 </>
281 ) 263 )
282 } 264 }
283 </div> 265 </div>
284 <div className='upload-run-buttons-container'> 266 <div className='upload-run-buttons-container'>
285 <button className={`${btn.defaultWide}`} onClick={_upload_run}>Submit</button> 267 <button className={`${btn.defaultWide}`} onClick={_upload_run}>Submit</button>
286 <button className={`${btn.defaultWide}`} onClick={() => onClose(false)}>Cancel</button> 268 <button className={`${btn.defaultWide}`} onClick={() => {
287 </div> 269 onClose(false);
270 setUploadRunContent({
271 host_demo: null,
272 partner_demo: null,
273 });
274 }}>Cancel</button>
275 </div>
288 </div> 276 </div>
289 </div> 277 </div>
290 </> 278 </>
diff --git a/frontend/src/pages/About.tsx b/frontend/src/pages/About.tsx
index fe2e25a..b7bd534 100644
--- a/frontend/src/pages/About.tsx
+++ b/frontend/src/pages/About.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from 'react-markdown';
3import { Helmet } from 'react-helmet';
3 4
4import '@css/About.css'; 5import '@css/About.css';
5 6
@@ -28,6 +29,9 @@ const About: React.FC = () => {
28 29
29 return ( 30 return (
30 <main> 31 <main>
32 <Helmet>
33 <title>LPHUB | About</title>
34 </Helmet>
31 <ReactMarkdown>{aboutText}</ReactMarkdown> 35 <ReactMarkdown>{aboutText}</ReactMarkdown>
32 </main> 36 </main>
33 ); 37 );
diff --git a/frontend/src/pages/Games.tsx b/frontend/src/pages/Games.tsx
index e0320af..5e0d5bf 100644
--- a/frontend/src/pages/Games.tsx
+++ b/frontend/src/pages/Games.tsx
@@ -1,4 +1,5 @@
1import React from 'react'; 1import React from 'react';
2import { Helmet } from 'react-helmet';
2 3
3import GameEntry from '@components/GameEntry'; 4import GameEntry from '@components/GameEntry';
4import { Game } from '@customTypes/Game'; 5import { Game } from '@customTypes/Game';
@@ -11,6 +12,9 @@ interface GamesProps {
11const Games: React.FC<GamesProps> = ({ games }) => { 12const Games: React.FC<GamesProps> = ({ games }) => {
12 return ( 13 return (
13 <main> 14 <main>
15 <Helmet>
16 <title>LPHUB | Games</title>
17 </Helmet>
14 <section> 18 <section>
15 <div className={gamesCSS.content}> 19 <div className={gamesCSS.content}>
16 {games.map((game, index) => ( 20 {games.map((game, index) => (
diff --git a/frontend/src/pages/Homepage.tsx b/frontend/src/pages/Homepage.tsx
index 68562b6..4f46af5 100644
--- a/frontend/src/pages/Homepage.tsx
+++ b/frontend/src/pages/Homepage.tsx
@@ -1,11 +1,15 @@
1import React from 'react'; 1import React from 'react';
2import { Helmet } from 'react-helmet';
2 3
3const Homepage: React.FC = () => { 4const Homepage: React.FC = () => {
4 5
5 return ( 6 return (
6 <main> 7 <main>
8 <Helmet>
9 <title>LPHUB | Homepage</title>
10 </Helmet>
7 <section> 11 <section>
8 <p/> 12 <p />
9 <h1>Welcome to Least Portals Hub!</h1> 13 <h1>Welcome to Least Portals Hub!</h1>
10 <p>At the moment, LPHUB is in beta state. This means that the site has only the core functionalities enabled for providing both collaborative information and competitive leaderboards.</p> 14 <p>At the moment, LPHUB is in beta state. This means that the site has only the core functionalities enabled for providing both collaborative information and competitive leaderboards.</p>
11 <p>The website should feel intuitive to navigate around. For any type of feedback, reach us at LPHUB Discord server.</p> 15 <p>The website should feel intuitive to navigate around. For any type of feedback, reach us at LPHUB Discord server.</p>
diff --git a/frontend/src/pages/Maplist.tsx b/frontend/src/pages/Maplist.tsx
index ecea3e1..b9e17f7 100644
--- a/frontend/src/pages/Maplist.tsx
+++ b/frontend/src/pages/Maplist.tsx
@@ -1,5 +1,6 @@
1import React, { useEffect } from "react"; 1import React, { useEffect } from "react";
2import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; 2import { Link, useLocation, useNavigate, useParams } from "react-router-dom";
3import { Helmet } from "react-helmet";
3 4
4import "@css/Maplist.css"; 5import "@css/Maplist.css";
5import { API } from "@api/Api"; 6import { API } from "@api/Api";
@@ -25,9 +26,9 @@ const Maplist: React.FC = () => {
25 const navigate = useNavigate(); 26 const navigate = useNavigate();
26 27
27 function _update_currently_selected(catNum2: number) { 28 function _update_currently_selected(catNum2: number) {
28 setCurrentlySelected(catNum2); 29 setCurrentlySelected(catNum2);
29 navigate("/games/" + game?.id + "?cat=" + catNum2); 30 navigate("/games/" + game?.id + "?cat=" + catNum2);
30 setHasClicked(true); 31 setHasClicked(true);
31 } 32 }
32 33
33 const _fetch_chapters = async (chapter_id: string) => { 34 const _fetch_chapters = async (chapter_id: string) => {
@@ -52,12 +53,12 @@ const Maplist: React.FC = () => {
52 // location query params 53 // location query params
53 const queryParams = new URLSearchParams(location.search); 54 const queryParams = new URLSearchParams(location.search);
54 if (queryParams.get("chapter")) { 55 if (queryParams.get("chapter")) {
55 let cat = parseFloat(queryParams.get("chapter") || ""); 56 let cat = parseFloat(queryParams.get("chapter") || "");
56 if (gameId == 2) { 57 if (gameId == 2) {
57 cat += 10; 58 cat += 10;
58 } 59 }
59 _fetch_chapters(cat.toString()); 60 _fetch_chapters(cat.toString());
60 } 61 }
61 62
62 const _fetch_game = async () => { 63 const _fetch_game = async () => {
63 const games = await API.get_games(); 64 const games = await API.get_games();
@@ -68,7 +69,7 @@ const Maplist: React.FC = () => {
68 setLoad(false); 69 setLoad(false);
69 } 70 }
70 }; 71 };
71 72
72 const _fetch_game_chapters = async () => { 73 const _fetch_game_chapters = async () => {
73 const games_chapters = await API.get_games_chapters(gameId.toString()); 74 const games_chapters = await API.get_games_chapters(gameId.toString());
74 setGameChapters(games_chapters); 75 setGameChapters(games_chapters);
@@ -81,7 +82,7 @@ const Maplist: React.FC = () => {
81 }, []); 82 }, []);
82 83
83 useEffect(() => { 84 useEffect(() => {
84 const queryParams = new URLSearchParams(location.search); 85 const queryParams = new URLSearchParams(location.search);
85 if (gameChapters != undefined && !queryParams.get("chapter")) { 86 if (gameChapters != undefined && !queryParams.get("chapter")) {
86 _fetch_chapters(gameChapters!.chapters[0].id.toString()); 87 _fetch_chapters(gameChapters!.chapters[0].id.toString());
87 } 88 }
@@ -97,6 +98,9 @@ const Maplist: React.FC = () => {
97 98
98 return ( 99 return (
99 <main> 100 <main>
101 <Helmet>
102 <title>LPHUB | Maplist</title>
103 </Helmet>
100 <section style={{ marginTop: "20px" }}> 104 <section style={{ marginTop: "20px" }}>
101 <Link to="/games"> 105 <Link to="/games">
102 <button className="nav-button" style={{ borderRadius: "20px" }}> 106 <button className="nav-button" style={{ borderRadius: "20px" }}>
@@ -129,7 +133,7 @@ const Maplist: React.FC = () => {
129 </div> 133 </div>
130 <div className="game-header-categories"> 134 <div className="game-header-categories">
131 {game?.category_portals.map((cat, index) => ( 135 {game?.category_portals.map((cat, index) => (
132 <button key={index} className={currentlySelected == cat.category.id || cat.category.id - 1 == catNum && !hasClicked ? "game-cat-button selected" : "game-cat-button"} onClick={() => {setCatNum(cat.category.id - 1); _update_currently_selected(cat.category.id)}}> 136 <button key={index} className={currentlySelected == cat.category.id || cat.category.id - 1 == catNum && !hasClicked ? "game-cat-button selected" : "game-cat-button"} onClick={() => { setCatNum(cat.category.id - 1); _update_currently_selected(cat.category.id) }}>
133 <span>{cat.category.name}</span> 137 <span>{cat.category.name}</span>
134 </button> 138 </button>
135 ))} 139 ))}
@@ -140,26 +144,26 @@ const Maplist: React.FC = () => {
140 <div> 144 <div>
141 <section className="chapter-select-container"> 145 <section className="chapter-select-container">
142 <div> 146 <div>
143 <span style={{fontSize: "18px", transform: "translateY(5px)", display: "block", marginTop: "10px"}}>{curChapter?.chapter.name.split(" - ")[0]}</span> 147 <span style={{ fontSize: "18px", transform: "translateY(5px)", display: "block", marginTop: "10px" }}>{curChapter?.chapter.name.split(" - ")[0]}</span>
144 </div> 148 </div>
145 <div onClick={_handle_dropdown_click} className="dropdown"> 149 <div onClick={_handle_dropdown_click} className="dropdown">
146 <span>{curChapter?.chapter.name.split(" - ")[1]}</span> 150 <span>{curChapter?.chapter.name.split(" - ")[1]}</span>
147 <i className="triangle"></i> 151 <i className="triangle"></i>
148 </div> 152 </div>
149 <div className="dropdown-elements" style={{display: dropdownActive}}> 153 <div className="dropdown-elements" style={{ display: dropdownActive }}>
150 {gameChapters?.chapters.map((chapter, i) => { 154 {gameChapters?.chapters.map((chapter, i) => {
151 return <div className="dropdown-element" onClick={() => {_fetch_chapters(chapter.id.toString()); _handle_dropdown_click()}}>{chapter.name}</div> 155 return <div className="dropdown-element" onClick={() => { _fetch_chapters(chapter.id.toString()); _handle_dropdown_click() }}>{chapter.name}</div>
152 }) 156 })
153 157
154 } 158 }
155 </div> 159 </div>
156 </section> 160 </section>
157 <section className="maplist"> 161 <section className="maplist">
158 {curChapter?.maps.map((map, i) => { 162 {curChapter?.maps.map((map, i) => {
159 return <div className="maplist-entry"> 163 return <div className="maplist-entry">
160 <Link to={`/maps/${map.id}`}> 164 <Link to={`/maps/${map.id}`}>
161 <span>{map.name}</span> 165 <span>{map.name}</span>
162 <div className="map-entry-image" style={{backgroundImage: `url(${map.image})`}}> 166 <div className="map-entry-image" style={{ backgroundImage: `url(${map.image})` }}>
163 <div className="blur map"> 167 <div className="blur map">
164 <span>{map.is_disabled ? map.category_portals[0].portal_count : map.category_portals.find( 168 <span>{map.is_disabled ? map.category_portals[0].portal_count : map.category_portals.find(
165 (obj) => obj.category.id === catNum + 1 169 (obj) => obj.category.id === catNum + 1
@@ -169,7 +173,7 @@ const Maplist: React.FC = () => {
169 </div> 173 </div>
170 <div className="difficulty-bar"> 174 <div className="difficulty-bar">
171 {/* <span>Difficulty:</span> */} 175 {/* <span>Difficulty:</span> */}
172 <div className={map.difficulty == 0 ? "one" : map.difficulty == 1 ? "two" : map.difficulty == 2 ? "three" : map.difficulty == 3 ? "four" : map.difficulty == 4 ? "five" : "one"}> 176 <div className={map.difficulty <= 2 ? "one" : map.difficulty <= 4 ? "two" : map.difficulty <= 6 ? "three" : map.difficulty <= 8 ? "four" : map.difficulty <= 10 ? "five" : "one"}>
173 <div className="difficulty-point"></div> 177 <div className="difficulty-point"></div>
174 <div className="difficulty-point"></div> 178 <div className="difficulty-point"></div>
175 <div className="difficulty-point"></div> 179 <div className="difficulty-point"></div>
@@ -177,9 +181,9 @@ const Maplist: React.FC = () => {
177 <div className="difficulty-point"></div> 181 <div className="difficulty-point"></div>
178 </div> 182 </div>
179 </div> 183 </div>
180 </Link> 184 </Link>
181 </div> 185 </div>
182 })} 186 })}
183 </section> 187 </section>
184 </div> 188 </div>
185 </section> 189 </section>
diff --git a/frontend/src/pages/Maps.tsx b/frontend/src/pages/Maps.tsx
index f1daa36..fb13563 100644
--- a/frontend/src/pages/Maps.tsx
+++ b/frontend/src/pages/Maps.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import { Link, useLocation } from 'react-router-dom'; 2import { Link, useLocation } from 'react-router-dom';
3import { Helmet } from 'react-helmet';
3 4
4import { PortalIcon, FlagIcon, ChatIcon } from '@images/Images'; 5import { PortalIcon, FlagIcon, ChatIcon } from '@images/Images';
5import Summary from '@components/Summary'; 6import Summary from '@components/Summary';
@@ -35,7 +36,7 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
35 }; 36 };
36 37
37 const _fetch_map_leaderboards = async () => { 38 const _fetch_map_leaderboards = async () => {
38 const mapLeaderboards = await API.get_map_leaderboard(mapID); 39 const mapLeaderboards = await API.get_map_leaderboard(mapID, "1");
39 setMapLeaderboardData(mapLeaderboards); 40 setMapLeaderboardData(mapLeaderboards);
40 }; 41 };
41 42
@@ -53,26 +54,32 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
53 if (!mapSummaryData) { 54 if (!mapSummaryData) {
54 // loading placeholder 55 // loading placeholder
55 return ( 56 return (
56 <main> 57 <>
57 <section id='section1' className='summary1'> 58 <main>
58 <div> 59 <section id='section1' className='summary1'>
59 <Link to="/games"><button className='nav-button' style={{ borderRadius: "20px 20px 20px 20px" }}><i className='triangle'></i><span>Games List</span></button></Link> 60 <div>
60 </div> 61 <Link to="/games"><button className='nav-button' style={{ borderRadius: "20px 20px 20px 20px" }}><i className='triangle'></i><span>Games List</span></button></Link>
61 </section> 62 </div>
62 63 </section>
63 <section id='section2' className='summary1'> 64
64 <button className='nav-button'><img src={PortalIcon} alt="" /><span>Summary</span></button> 65 <section id='section2' className='summary1'>
65 <button className='nav-button'><img src={FlagIcon} alt="" /><span>Leaderboards</span></button> 66 <button className='nav-button'><img src={PortalIcon} alt="" /><span>Summary</span></button>
66 <button className='nav-button'><img src={ChatIcon} alt="" /><span>Discussions</span></button> 67 <button className='nav-button'><img src={FlagIcon} alt="" /><span>Leaderboards</span></button>
67 </section> 68 <button className='nav-button'><img src={ChatIcon} alt="" /><span>Discussions</span></button>
68 69 </section>
69 <section id='section6' className='summary2' /> 70
70 </main> 71 <section id='section6' className='summary2' />
72 </main>
73 </>
71 ); 74 );
72 } 75 }
73 76
74 return ( 77 return (
75 <> 78 <>
79 <Helmet>
80 <title>LPHUB | {mapSummaryData.map.map_name}</title>
81 <meta name="description" content={mapSummaryData.map.map_name} />
82 </Helmet>
76 {isModerator && <ModMenu token={token} data={mapSummaryData} selectedRun={selectedRun} mapID={mapID} />} 83 {isModerator && <ModMenu token={token} data={mapSummaryData} selectedRun={selectedRun} mapID={mapID} />}
77 84
78 <div id='background-image'> 85 <div id='background-image'>
@@ -94,7 +101,7 @@ const Maps: React.FC<MapProps> = ({ token, isModerator }) => {
94 </section> 101 </section>
95 102
96 {navState === 0 && <Summary selectedRun={selectedRun} setSelectedRun={setSelectedRun} data={mapSummaryData} />} 103 {navState === 0 && <Summary selectedRun={selectedRun} setSelectedRun={setSelectedRun} data={mapSummaryData} />}
97 {navState === 1 && <Leaderboards data={mapLeaderboardData} />} 104 {navState === 1 && <Leaderboards mapID={mapID} />}
98 {navState === 2 && <Discussions data={mapDiscussionsData} token={token} isModerator={isModerator} mapID={mapID} onRefresh={() => _fetch_map_discussions()} />} 105 {navState === 2 && <Discussions data={mapDiscussionsData} token={token} isModerator={isModerator} mapID={mapID} onRefresh={() => _fetch_map_discussions()} />}
99 </main> 106 </main>
100 </> 107 </>
diff --git a/frontend/src/pages/Profile.tsx b/frontend/src/pages/Profile.tsx
index 00d8f4e..ee56999 100644
--- a/frontend/src/pages/Profile.tsx
+++ b/frontend/src/pages/Profile.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import { Link, useNavigate } from 'react-router-dom'; 2import { Link, useNavigate } from 'react-router-dom';
3import { Helmet } from 'react-helmet';
3 4
4import { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon, DeleteIcon } from '@images/Images'; 5import { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon, DeleteIcon } from '@images/Images';
5import { UserProfile } from '@customTypes/Profile'; 6import { UserProfile } from '@customTypes/Profile';
@@ -109,6 +110,10 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
109 110
110 return ( 111 return (
111 <div style={{position: "absolute", width: "calc(100% - 50px)", left: "350px"}}> 112 <div style={{position: "absolute", width: "calc(100% - 50px)", left: "350px"}}>
113 <Helmet>
114 <title>LPHUB | {profile.user_name}</title>
115 <meta name="description" content={profile.user_name} />
116 </Helmet>
112 {MessageDialogComponent} 117 {MessageDialogComponent}
113 {MessageDialogLoadComponent} 118 {MessageDialogLoadComponent}
114 {ConfirmDialogComponent} 119 {ConfirmDialogComponent}
@@ -267,7 +272,7 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
267 272
268 <span style={{ display: "grid" }}>{e.score_count}</span> 273 <span style={{ display: "grid" }}>{e.score_count}</span>
269 274
270 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count > 0 ? `+${e.score_count - r.map_wr_count}` : e.score_count - r.map_wr_count}</span> 275 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count > 0 ? `+${e.score_count - r.map_wr_count}` : `-`}</span>
271 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span> 276 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span>
272 <span> </span> 277 <span> </span>
273 {i === 0 ? <span>#{r.placement}</span> : <span> </span>} 278 {i === 0 ? <span>#{r.placement}</span> : <span> </span>}
@@ -313,7 +318,7 @@ const Profile: React.FC<ProfileProps> = ({ profile, token, gameData, onDeleteRec
313 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""} 318 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""}
314 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link> 319 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link>
315 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span> 320 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span>
316 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count > 0 ? `+${record!.scores[i].score_count - record!.map_wr_count}` : record!.scores[i].score_count - record!.map_wr_count}</span> 321 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count > 0 ? `+${record!.scores[i].score_count - record!.map_wr_count}` : `-`}</span>
317 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span> 322 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span>
318 <span> </span> 323 <span> </span>
319 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>} 324 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>}
diff --git a/frontend/src/pages/Rankings.tsx b/frontend/src/pages/Rankings.tsx
index cdb87a8..71aa427 100644
--- a/frontend/src/pages/Rankings.tsx
+++ b/frontend/src/pages/Rankings.tsx
@@ -1,4 +1,5 @@
1import React, { useEffect } from "react"; 1import React, { useEffect } from "react";
2import { Helmet } from "react-helmet";
2 3
3import RankingEntry from "@components/RankingEntry"; 4import RankingEntry from "@components/RankingEntry";
4import { Ranking, SteamRanking, RankingType, SteamRankingType } from "@customTypes/Ranking"; 5import { Ranking, SteamRanking, RankingType, SteamRankingType } from "@customTypes/Ranking";
@@ -13,9 +14,9 @@ const Rankings: React.FC = () => {
13 official, 14 official,
14 unofficial 15 unofficial
15 } 16 }
16 const [currentRankingType, setCurrentRankingType] = React.useState<LeaderboardTypes>(LeaderboardTypes.official); 17 const [currentRankingType, setCurrentRankingType] = React.useState<LeaderboardTypes>(LeaderboardTypes.official);
17 18
18 const [leaderboardLoad, setLeaderboardLoad] = React.useState<boolean>(false); 19 const [leaderboardLoad, setLeaderboardLoad] = React.useState<boolean>(false);
19 20
20 enum RankingCategories { 21 enum RankingCategories {
21 rankings_overall, 22 rankings_overall,
@@ -26,7 +27,7 @@ const Rankings: React.FC = () => {
26 const [load, setLoad] = React.useState<boolean>(false); 27 const [load, setLoad] = React.useState<boolean>(false);
27 28
28 const _fetch_rankings = async () => { 29 const _fetch_rankings = async () => {
29 setLeaderboardLoad(false); 30 setLeaderboardLoad(false);
30 const rankings = await API.get_official_rankings(); 31 const rankings = await API.get_official_rankings();
31 setLeaderboardData(rankings); 32 setLeaderboardData(rankings);
32 if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { 33 if (currentLeaderboardType == RankingCategories.rankings_singleplayer) {
@@ -37,12 +38,12 @@ const Rankings: React.FC = () => {
37 setCurrentLeaderboard(rankings.rankings_overall) 38 setCurrentLeaderboard(rankings.rankings_overall)
38 } 39 }
39 setLoad(true); 40 setLoad(true);
40 setLeaderboardLoad(true); 41 setLeaderboardLoad(true);
41 } 42 }
42 43
43 const __dev_fetch_unofficial_rankings = async () => { 44 const __dev_fetch_unofficial_rankings = async () => {
44 try { 45 try {
45 setLeaderboardLoad(false); 46 setLeaderboardLoad(false);
46 const rankings = await API.get_unofficial_rankings(); 47 const rankings = await API.get_unofficial_rankings();
47 setLeaderboardData(rankings); 48 setLeaderboardData(rankings);
48 if (currentLeaderboardType == RankingCategories.rankings_singleplayer) { 49 if (currentLeaderboardType == RankingCategories.rankings_singleplayer) {
@@ -53,7 +54,7 @@ const Rankings: React.FC = () => {
53 } else { 54 } else {
54 setCurrentLeaderboard(rankings.rankings_overall) 55 setCurrentLeaderboard(rankings.rankings_overall)
55 } 56 }
56 setLeaderboardLoad(true); 57 setLeaderboardLoad(true);
57 } catch (e) { 58 } catch (e) {
58 console.log(e) 59 console.log(e)
59 } 60 }
@@ -88,12 +89,15 @@ const Rankings: React.FC = () => {
88 89
89 return ( 90 return (
90 <main> 91 <main>
92 <Helmet>
93 <title>LPHUB | Rankings</title>
94 </Helmet>
91 <section className="nav-container nav-1"> 95 <section className="nav-container nav-1">
92 <div> 96 <div>
93 <button onClick={() => {_fetch_rankings(); setCurrentRankingType(LeaderboardTypes.official)}} className={`nav-1-btn ${currentRankingType == LeaderboardTypes.official ? "selected" : ""}`}> 97 <button onClick={() => { _fetch_rankings(); setCurrentRankingType(LeaderboardTypes.official) }} className={`nav-1-btn ${currentRankingType == LeaderboardTypes.official ? "selected" : ""}`}>
94 <span>Official (LPHUB)</span> 98 <span>Official (LPHUB)</span>
95 </button> 99 </button>
96 <button onClick={() => {__dev_fetch_unofficial_rankings(); setCurrentRankingType(LeaderboardTypes.unofficial)}} className={`nav-1-btn ${currentRankingType == LeaderboardTypes.unofficial ? "selected" : ""}`}> 100 <button onClick={() => { __dev_fetch_unofficial_rankings(); setCurrentRankingType(LeaderboardTypes.unofficial) }} className={`nav-1-btn ${currentRankingType == LeaderboardTypes.unofficial ? "selected" : ""}`}>
97 <span>Unofficial (Steam)</span> 101 <span>Unofficial (Steam)</span>
98 </button> 102 </button>
99 </div> 103 </div>
@@ -128,11 +132,11 @@ const Rankings: React.FC = () => {
128 }) 132 })
129 } 133 }
130 134
131 {leaderboardLoad ? null : 135 {leaderboardLoad ? null :
132 <div style={{display: "flex", justifyContent: "center", margin: "30px 0px"}}> 136 <div style={{ display: "flex", justifyContent: "center", margin: "30px 0px" }}>
133 <span className="loader"></span> 137 <span className="loader"></span>
134 </div> 138 </div>
135 } 139 }
136 </div> 140 </div>
137 </section> 141 </section>
138 : null} 142 : null}
diff --git a/frontend/src/pages/Rules.tsx b/frontend/src/pages/Rules.tsx
index b5625ce..9f57b7e 100644
--- a/frontend/src/pages/Rules.tsx
+++ b/frontend/src/pages/Rules.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import ReactMarkdown from 'react-markdown'; 2import ReactMarkdown from 'react-markdown';
3import { Helmet } from 'react-helmet';
3 4
4import '@css/Rules.css'; 5import '@css/Rules.css';
5 6
@@ -29,6 +30,9 @@ const Rules: React.FC = () => {
29 30
30 return ( 31 return (
31 <main> 32 <main>
33 <Helmet>
34 <title>LPHUB | Rules</title>
35 </Helmet>
32 <ReactMarkdown>{rulesText}</ReactMarkdown> 36 <ReactMarkdown>{rulesText}</ReactMarkdown>
33 </main> 37 </main>
34 ); 38 );
diff --git a/frontend/src/pages/User.tsx b/frontend/src/pages/User.tsx
index f90d1aa..d43c0c6 100644
--- a/frontend/src/pages/User.tsx
+++ b/frontend/src/pages/User.tsx
@@ -1,5 +1,6 @@
1import React from 'react'; 1import React from 'react';
2import { Link, useLocation, useNavigate } from 'react-router-dom'; 2import { Link, useLocation, useNavigate } from 'react-router-dom';
3import { Helmet } from 'react-helmet';
3 4
4import { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon } from '@images/Images'; 5import { SteamIcon, TwitchIcon, YouTubeIcon, PortalIcon, FlagIcon, StatisticsIcon, SortIcon, ThreedotIcon, DownloadIcon, HistoryIcon } from '@images/Images';
5import { UserProfile } from '@customTypes/Profile'; 6import { UserProfile } from '@customTypes/Profile';
@@ -92,6 +93,10 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
92 93
93 return ( 94 return (
94 <main> 95 <main>
96 <Helmet>
97 <title>LPHUB | {user.user_name}</title>
98 <meta name="description" content={user.user_name} />
99 </Helmet>
95 {MessageDialogComponent} 100 {MessageDialogComponent}
96 <section id='section1' className='profile'> 101 <section id='section1' className='profile'>
97 <div> 102 <div>
@@ -236,7 +241,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
236 241
237 <span style={{ display: "grid" }}>{e.score_count}</span> 242 <span style={{ display: "grid" }}>{e.score_count}</span>
238 243
239 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count > 0 ? `+${e.score_count - r.map_wr_count}` : e.score_count - r.map_wr_count}</span> 244 <span style={{ display: "grid" }}>{e.score_count - r.map_wr_count > 0 ? `+${e.score_count - r.map_wr_count}` : `-`}</span>
240 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span> 245 <span style={{ display: "grid" }}>{ticks_to_time(e.score_time)}</span>
241 <span> </span> 246 <span> </span>
242 {i === 0 ? <span>#{r.placement}</span> : <span> </span>} 247 {i === 0 ? <span>#{r.placement}</span> : <span> </span>}
@@ -281,7 +286,7 @@ const User: React.FC<UserProps> = ({ token, profile, gameData }) => {
281 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""} 286 {i !== 0 ? <hr style={{ gridColumn: "1 / span 8" }} /> : ""}
282 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link> 287 <Link to={`/maps/${r.id}`}><span>{r.name}</span></Link>
283 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span> 288 <span style={{ display: "grid" }}>{record!.scores[i].score_count}</span>
284 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count > 0 ? `+${record!.scores[i].score_count - record!.map_wr_count}` : record!.scores[i].score_count - record!.map_wr_count}</span> 289 <span style={{ display: "grid" }}>{record!.scores[i].score_count - record!.map_wr_count > 0 ? `+${record!.scores[i].score_count - record!.map_wr_count}` : `-`}</span>
285 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span> 290 <span style={{ display: "grid" }}>{ticks_to_time(record!.scores[i].score_time)}</span>
286 <span> </span> 291 <span> </span>
287 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>} 292 {i === 0 ? <span>#{record!.placement}</span> : <span> </span>}
diff --git a/frontend/src/types/Content.ts b/frontend/src/types/Content.ts
index 42a6917..775fab4 100644
--- a/frontend/src/types/Content.ts
+++ b/frontend/src/types/Content.ts
@@ -18,7 +18,6 @@ export interface MapDiscussionCommentContent {
18}; 18};
19 19
20export interface UploadRunContent { 20export interface UploadRunContent {
21 map_id: number;
22 host_demo: File | null; 21 host_demo: File | null;
23 partner_demo: File | null; 22 partner_demo: File | null;
24}; 23};
diff --git a/frontend/src/types/Map.ts b/frontend/src/types/Map.ts
index 89c66d5..4f8eabf 100644
--- a/frontend/src/types/Map.ts
+++ b/frontend/src/types/Map.ts
@@ -79,6 +79,7 @@ interface MapSummaryMap {
79 map_name: string; 79 map_name: string;
80 is_coop: boolean; 80 is_coop: boolean;
81 is_disabled: boolean; 81 is_disabled: boolean;
82 difficulty: number;
82}; 83};
83 84
84interface MapSummaryDetails { 85interface MapSummaryDetails {
diff --git a/frontend/src/types/MapNames.ts b/frontend/src/types/MapNames.ts
new file mode 100644
index 0000000..b6313e7
--- /dev/null
+++ b/frontend/src/types/MapNames.ts
@@ -0,0 +1,127 @@
1export const MapNames: { [key: string]: number } = {
2 "sp_a1_intro1": 1,
3 "sp_a1_intro2": 2,
4 "sp_a1_intro3": 3,
5 "sp_a1_intro4": 4,
6 "sp_a1_intro5": 5,
7 "sp_a1_intro6": 6,
8 "sp_a1_intro7": 7,
9 "sp_a1_wakeup": 8,
10 "sp_a2_intro": 9,
11
12 "sp_a2_laser_intro": 10,
13 "sp_a2_laser_stairs": 11,
14 "sp_a2_dual_lasers": 12,
15 "sp_a2_laser_over_goo": 13,
16 "sp_a2_catapult_intro": 14,
17 "sp_a2_trust_fling": 15,
18 "sp_a2_pit_flings": 16,
19 "sp_a2_fizzler_intro": 17,
20
21 "sp_a2_sphere_peek": 18,
22 "sp_a2_ricochet": 19,
23 "sp_a2_bridge_intro": 20,
24 "sp_a2_bridge_the_gap": 21,
25 "sp_a2_turret_intro": 22,
26 "sp_a2_laser_relays": 23,
27 "sp_a2_turret_blocker": 24,
28 "sp_a2_laser_vs_turret": 25,
29 "sp_a2_pull_the_rug": 26,
30
31 "sp_a2_column_blocker": 27,
32 "sp_a2_laser_chaining": 28,
33 "sp_a2_triple_laser": 29,
34 "sp_a2_bts1": 30,
35 "sp_a2_bts2": 31,
36
37 "sp_a2_bts3": 32,
38 "sp_a2_bts4": 33,
39 "sp_a2_bts5": 34,
40 "sp_a2_core": 35,
41
42 "sp_a3_01": 36,
43 "sp_a3_03": 37,
44 "sp_a3_jump_intro": 38,
45 "sp_a3_bomb_flings": 39,
46 "sp_a3_crazy_box": 40,
47 "sp_a3_transition01": 41,
48
49 "sp_a3_speed_ramp": 42,
50 "sp_a3_speed_flings": 43,
51 "sp_a3_portal_intro": 44,
52 "sp_a3_end": 45,
53
54 "sp_a4_intro": 46,
55 "sp_a4_tb_intro": 47,
56 "sp_a4_tb_trust_drop": 48,
57 "sp_a4_tb_wall_button": 49,
58 "sp_a4_tb_polarity": 50,
59 "sp_a4_tb_catch": 51,
60 "sp_a4_stop_the_box": 52,
61 "sp_a4_laser_catapult": 53,
62 "sp_a4_laser_platform": 54,
63 "sp_a4_speed_tb_catch": 55,
64 "sp_a4_jump_polarity": 56,
65
66 "sp_a4_finale1": 57,
67 "sp_a4_finale2": 58,
68 "sp_a4_finale3": 59,
69 "sp_a4_finale4": 60,
70
71 "mp_coop_start": 61,
72 "mp_coop_lobby_3": 62,
73
74 "mp_coop_doors": 63,
75 "mp_coop_race_2": 64,
76 "mp_coop_laser_2": 65,
77 "mp_coop_rat_maze": 66,
78 "mp_coop_laser_crusher": 67,
79 "mp_coop_teambts": 68,
80
81 "mp_coop_fling_3": 69,
82 "mp_coop_infinifling_train": 70,
83 "mp_coop_come_along": 71,
84 "mp_coop_fling_1": 72,
85 "mp_coop_catapult_1": 73,
86 "mp_coop_multifling_1": 74,
87 "mp_coop_fling_crushers": 75,
88 "mp_coop_fan": 76,
89
90 "mp_coop_wall_intro": 77,
91 "mp_coop_wall_2": 78,
92 "mp_coop_catapult_wall_intro": 79,
93 "mp_coop_wall_block": 80,
94 "mp_coop_catapult_2": 81,
95 "mp_coop_turret_walls": 82,
96 "mp_coop_turret_ball": 83,
97 "mp_coop_wall_5": 84,
98
99 "mp_coop_tbeam_redirect": 85,
100 "mp_coop_tbeam_drill": 86,
101 "mp_coop_tbeam_catch_grind_1": 87,
102 "mp_coop_tbeam_laser_1": 88,
103 "mp_coop_tbeam_polarity": 89,
104 "mp_coop_tbeam_polarity2": 90,
105 "mp_coop_tbeam_polarity3": 91,
106 "mp_coop_tbeam_maze": 92,
107 "mp_coop_tbeam_end": 93,
108
109 "mp_coop_paint_come_along": 94,
110 "mp_coop_paint_redirect": 95,
111 "mp_coop_paint_bridge": 96,
112 "mp_coop_paint_walljumps": 97,
113 "mp_coop_paint_speed_fling": 98,
114 "mp_coop_paint_red_racer": 99,
115 "mp_coop_paint_speed_catch": 100,
116 "mp_coop_paint_longjump_intro": 101,
117
118 "mp_coop_separation_1": 102,
119 "mp_coop_tripleaxis": 103,
120 "mp_coop_catapult_catch": 104,
121 "mp_coop_2paints_1bridge": 105,
122 "mp_coop_paint_conversion": 106,
123 "mp_coop_bridge_catch": 107,
124 "mp_coop_laser_tbeam": 108,
125 "mp_coop_paint_rat_maze": 109,
126 "mp_coop_paint_crazy_box": 110,
127};
diff --git a/rankings/fetch.go b/rankings/fetch.go
index 7e63427..7e9a449 100644
--- a/rankings/fetch.go
+++ b/rankings/fetch.go
@@ -3,6 +3,7 @@ package main
3import ( 3import (
4 "encoding/json" 4 "encoding/json"
5 "encoding/xml" 5 "encoding/xml"
6 "errors"
6 "fmt" 7 "fmt"
7 "io" 8 "io"
8 "log" 9 "log"
@@ -12,7 +13,12 @@ import (
12 "strings" 13 "strings"
13) 14)
14 15
15func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, useCache bool) map[SteamID]*Player { 16var (
17 errLb error = errors.New("leaderboards error")
18 errPi error = errors.New("playerinfo error")
19)
20
21func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, useCache bool) (map[SteamID]*Player, error) {
16 log.Println("fetching leaderboard") 22 log.Println("fetching leaderboard")
17 players := map[SteamID]*Player{} 23 players := map[SteamID]*Player{}
18 // first init players map with records from portal gun and doors 24 // first init players map with records from portal gun and doors
@@ -21,7 +27,10 @@ func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, us
21 end := 5000 27 end := 5000
22 28
23 for fetchAnotherPage { 29 for fetchAnotherPage {
24 portalGunEntries := fetchRecordsFromMap(47459, 0, 5000, useCache) 30 portalGunEntries, err := fetchRecordsFromMap(47459, 0, 5000, useCache)
31 if err != nil {
32 return nil, err
33 }
25 fetchAnotherPage = portalGunEntries.needsAnotherPage(&records[0]) 34 fetchAnotherPage = portalGunEntries.needsAnotherPage(&records[0])
26 if fetchAnotherPage { 35 if fetchAnotherPage {
27 start = end + 1 36 start = end + 1
@@ -50,7 +59,10 @@ func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, us
50 end = 5000 59 end = 5000
51 60
52 for fetchAnotherPage { 61 for fetchAnotherPage {
53 doorsEntries := fetchRecordsFromMap(47740, start, end, useCache) 62 doorsEntries, err := fetchRecordsFromMap(47740, start, end, useCache)
63 if err != nil {
64 return nil, err
65 }
54 fetchAnotherPage = doorsEntries.needsAnotherPage(&records[51]) 66 fetchAnotherPage = doorsEntries.needsAnotherPage(&records[51])
55 if fetchAnotherPage { 67 if fetchAnotherPage {
56 start = end + 1 68 start = end + 1
@@ -94,7 +106,10 @@ func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, us
94 end := 5000 106 end := 5000
95 107
96 for fetchAnotherPage { 108 for fetchAnotherPage {
97 entries := fetchRecordsFromMap(record.MapID, start, end, useCache) 109 entries, err := fetchRecordsFromMap(record.MapID, start, end, useCache)
110 if err != nil {
111 return nil, err
112 }
98 fetchAnotherPage = entries.needsAnotherPage(&record) 113 fetchAnotherPage = entries.needsAnotherPage(&record)
99 if fetchAnotherPage { 114 if fetchAnotherPage {
100 start = end + 1 115 start = end + 1
@@ -137,10 +152,10 @@ func fetchLeaderboard(records []Record, overrides map[SteamID]map[string]int, us
137 } 152 }
138 153
139 } 154 }
140 return players 155 return players, nil
141} 156}
142 157
143func fetchRecordsFromMap(mapID int, start int, end int, useCache bool) *Leaderboard { 158func fetchRecordsFromMap(mapID int, start int, end int, useCache bool) (*Leaderboard, error) {
144 var filename string 159 var filename string
145 if useCache { 160 if useCache {
146 filename := fmt.Sprintf("./cache/lb_%d_%d_%d.xml", mapID, start, end) 161 filename := fmt.Sprintf("./cache/lb_%d_%d_%d.xml", mapID, start, end)
@@ -152,25 +167,27 @@ func fetchRecordsFromMap(mapID int, start int, end int, useCache bool) *Leaderbo
152 if err != nil { 167 if err != nil {
153 log.Fatalln("failed to unmarshal cache.", err.Error()) 168 log.Fatalln("failed to unmarshal cache.", err.Error())
154 } 169 }
155 return &leaderboard 170 return &leaderboard, nil
156 } 171 }
157 } 172 }
158 173
159 url := fmt.Sprintf("https://steamcommunity.com/stats/Portal2/leaderboards/%d?xml=1&start=%d&end=%d", mapID, start, end) 174 url := fmt.Sprintf("https://steamcommunity.com/stats/Portal2/leaderboards/%d?xml=1&start=%d&end=%d", mapID, start, end)
160 resp, err := http.Get(url) 175 resp, err := http.Get(url)
161 log.Println("fetched", url, ":", resp.StatusCode)
162 if err != nil { 176 if err != nil {
163 log.Fatalln("failed to fetch leaderboard.", err.Error()) 177 log.Println("failed to fetch leaderboard.", err.Error())
178 return nil, errLb
164 } 179 }
165 respBytes, err := io.ReadAll(resp.Body) 180 respBytes, err := io.ReadAll(resp.Body)
166 if err != nil { 181 if err != nil {
167 log.Fatalln("failed to read leadeboard body.", err.Error()) 182 log.Println("failed to read leadeboard body.", err.Error())
183 return nil, errLb
168 } 184 }
169 leaderboard := Leaderboard{} 185 leaderboard := Leaderboard{}
170 err = xml.Unmarshal(respBytes, &leaderboard) 186 err = xml.Unmarshal(respBytes, &leaderboard)
171 if err != nil { 187 if err != nil {
172 log.Println(string(respBytes)) 188 log.Println(string(respBytes))
173 log.Fatalln("failed to unmarshal leaderboard.", err.Error()) 189 log.Println("failed to unmarshal leaderboard.", err.Error())
190 return nil, errLb
174 } 191 }
175 192
176 if useCache { 193 if useCache {
@@ -179,10 +196,10 @@ func fetchRecordsFromMap(mapID int, start int, end int, useCache bool) *Leaderbo
179 } 196 }
180 } 197 }
181 198
182 return &leaderboard 199 return &leaderboard, nil
183} 200}
184 201
185func fetchPlayerInfo(players []*Player) { 202func fetchPlayerInfo(players []*Player) error {
186 log.Println("fetching info for", len(players), "players") 203 log.Println("fetching info for", len(players), "players")
187 204
188 ids := make([]string, len(players)) 205 ids := make([]string, len(players))
@@ -193,11 +210,13 @@ func fetchPlayerInfo(players []*Player) {
193 url := fmt.Sprintf("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=%s&steamids=%s", os.Getenv("API_KEY"), strings.Join(ids, ",")) 210 url := fmt.Sprintf("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=%s&steamids=%s", os.Getenv("API_KEY"), strings.Join(ids, ","))
194 resp, err := http.Get(url) 211 resp, err := http.Get(url)
195 if err != nil { 212 if err != nil {
196 log.Fatalln(err.Error()) 213 log.Println(err.Error())
214 return errPi
197 } 215 }
198 body, err := io.ReadAll(resp.Body) 216 body, err := io.ReadAll(resp.Body)
199 if err != nil { 217 if err != nil {
200 log.Fatalln(err.Error()) 218 log.Println(err.Error())
219 return errPi
201 } 220 }
202 type PlayerSummary struct { 221 type PlayerSummary struct {
203 SteamID SteamID `json:"steamid"` 222 SteamID SteamID `json:"steamid"`
@@ -223,4 +242,5 @@ func fetchPlayerInfo(players []*Player) {
223 } 242 }
224 } 243 }
225 } 244 }
245 return nil
226} 246}
diff --git a/rankings/input/records.json b/rankings/input/records.json
index 884fd49..2b1fb21 100644
--- a/rankings/input/records.json
+++ b/rankings/input/records.json
@@ -298,7 +298,7 @@
298 "id": 47822, 298 "id": 47822,
299 "name": "Finale 2", 299 "name": "Finale 2",
300 "mode": 1, 300 "mode": 1,
301 "wr": 2 301 "wr": 0
302 }, 302 },
303 { 303 {
304 "id": 47823, 304 "id": 47823,
@@ -377,7 +377,7 @@
377 "id": 47839, 377 "id": 47839,
378 "name": "Catapults", 378 "name": "Catapults",
379 "mode": 2, 379 "mode": 2,
380 "wr": 4 380 "wr": 3
381 }, 381 },
382 { 382 {
383 "id": 47842, 383 "id": 47842,
diff --git a/rankings/main.go b/rankings/main.go
index 552f058..928d3be 100644
--- a/rankings/main.go
+++ b/rankings/main.go
@@ -58,7 +58,10 @@ func run() {
58 overrides := readOverrides() 58 overrides := readOverrides()
59 log.Println("loaded", len(overrides), "player overrides") 59 log.Println("loaded", len(overrides), "player overrides")
60 60
61 players := fetchLeaderboard(records, overrides, useCache) 61 players, err := fetchLeaderboard(records, overrides, useCache)
62 if err != nil {
63 return
64 }
62 65
63 spRankings := []*Player{} 66 spRankings := []*Player{}
64 mpRankings := []*Player{} 67 mpRankings := []*Player{}