├── docs ├── example1.png ├── example2.png ├── stats.md └── changelog.md ├── cspy_rest_api ├── requirements.txt ├── static │ ├── favicon.ico │ └── style.css ├── users_and_matches.db ├── src │ ├── sql_setup_deployment.py │ ├── user_data_payload.py │ ├── flask_api_server.py │ └── sql_db_manager.py ├── check_db.py ├── templates │ └── index.html └── all_data.txt ├── cspy_client_app ├── requirements.txt ├── static │ ├── favicon.ico │ └── style.css ├── logs │ ├── server_log.txt │ └── rounds_json.txt ├── src │ ├── setup.py │ ├── game_state_payload.py │ ├── flask_user_app.py │ ├── match_analysis.py │ └── sql_data_processing.py └── templates │ └── index.html ├── required_user_files ├── VCRUNTIME140.dll ├── gamestate_integration_main.cfg └── README.txt ├── dev_testing ├── sample_matches │ ├── train_no_dupes.db │ ├── inferno_two_dupes.db │ ├── cache2_one_duplicate.db │ ├── mirage2_missing_two_rounds.db │ ├── cache4_ct_t_sides_fix_success.db │ ├── overpass_assists_cause_dupes.db │ ├── forgot_to_rtn_false_2_2_last_round.db │ ├── overpass2_one_duplicate_from_bot.db │ └── overpass4_two_missing_and_one_dupe.db ├── sample_json │ ├── alive_end_round.json │ ├── endgame_diff_player_data.json │ ├── dead_midround_data.json │ └── invalid_data.json ├── script_samples.py └── testing_log.txt ├── LICENSE ├── .gitignore └── README.md /docs/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/docs/example1.png -------------------------------------------------------------------------------- /docs/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/docs/example2.png -------------------------------------------------------------------------------- /cspy_rest_api/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask_RESTful>=0.3.6 2 | pandas>=0.23.3 3 | Flask>=1.0.2 4 | -------------------------------------------------------------------------------- /cspy_client_app/requirements.txt: -------------------------------------------------------------------------------- 1 | pandas>=0.23.3 2 | requests>=2.19.1 3 | Flask>=1.0.2 4 | cx_Freeze>=5.1.1 5 | -------------------------------------------------------------------------------- /cspy_client_app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/cspy_client_app/static/favicon.ico -------------------------------------------------------------------------------- /cspy_rest_api/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/cspy_rest_api/static/favicon.ico -------------------------------------------------------------------------------- /cspy_rest_api/users_and_matches.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/cspy_rest_api/users_and_matches.db -------------------------------------------------------------------------------- /required_user_files/VCRUNTIME140.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/required_user_files/VCRUNTIME140.dll -------------------------------------------------------------------------------- /dev_testing/sample_matches/train_no_dupes.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/train_no_dupes.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/inferno_two_dupes.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/inferno_two_dupes.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/cache2_one_duplicate.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/cache2_one_duplicate.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/mirage2_missing_two_rounds.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/mirage2_missing_two_rounds.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/cache4_ct_t_sides_fix_success.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/cache4_ct_t_sides_fix_success.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/overpass_assists_cause_dupes.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/overpass_assists_cause_dupes.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/forgot_to_rtn_false_2_2_last_round.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/forgot_to_rtn_false_2_2_last_round.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/overpass2_one_duplicate_from_bot.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/overpass2_one_duplicate_from_bot.db -------------------------------------------------------------------------------- /dev_testing/sample_matches/overpass4_two_missing_and_one_dupe.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Parkkeo1/CS-Py/HEAD/dev_testing/sample_matches/overpass4_two_missing_and_one_dupe.db -------------------------------------------------------------------------------- /cspy_rest_api/src/sql_setup_deployment.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | from flask_api_server import cs_py_server 4 | from sql_db_manager import server_sql_setup 5 | 6 | # Standalone script for deploying on PythonAnywhere 7 | server_sql_setup(sqlite3.connect(cs_py_server.config['DATABASE'])) 8 | -------------------------------------------------------------------------------- /cspy_client_app/logs/server_log.txt: -------------------------------------------------------------------------------- 1 | Round Duplicate Not Inserted 2 | Match Data Sent; Rounds Reset 3 | --- 4 | 5 | Round Duplicate Not Inserted 6 | Match Data Sent; Rounds Reset 7 | --- 8 | 9 | Match Data Sent; Rounds Reset 10 | --- 11 | 12 | Round Duplicate Not Inserted 13 | Match Data Sent; Rounds Reset 14 | --- 15 | 16 | -------------------------------------------------------------------------------- /required_user_files/gamestate_integration_main.cfg: -------------------------------------------------------------------------------- 1 | "CS-Py" 2 | { 3 | "uri" "http://127.0.0.1:5000/GS" 4 | "timeout" "5.0" 5 | "buffer" "0.1" 6 | "throttle" "0.5" 7 | "heartbeat" "90.0" 8 | "data" 9 | { 10 | "provider" "1" 11 | "map" "1" 12 | "round" "1" 13 | "player_id" "1" 14 | "player_state" "1" 15 | "player_match_stats" "1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /cspy_rest_api/check_db.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import sqlite3 3 | 4 | pd.set_option('display.height', 1000) 5 | pd.set_option('display.max_rows', 500) 6 | pd.set_option('display.max_columns', 500) 7 | pd.set_option('display.width', 1000) 8 | 9 | conn = sqlite3.connect('users_and_matches.db') 10 | all_matches_df = pd.read_sql('SELECT * FROM all_matches;', conn) 11 | all_users_df = pd.read_sql('SELECT * FROM all_users;', conn) 12 | 13 | print(all_users_df, file=open('all_data.txt', 'w')) 14 | print('\n', file=open('all_data.txt', 'a')) 15 | print(all_matches_df, file=open('all_data.txt', 'a')) 16 | 17 | # Deletes Last Entered Entry 18 | # cur = conn.cursor() 19 | # cur.execute('DELETE FROM all_matches WHERE Match_ID = (SELECT MAX(Match_ID) FROM all_matches)') 20 | # conn.commit() 21 | -------------------------------------------------------------------------------- /cspy_client_app/static/style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | background-color: #202020; 5 | font-family: Roboto, sans-serif; 6 | } 7 | 8 | body { 9 | color: #C0C0C0; 10 | text-align: center; 11 | } 12 | 13 | form { 14 | display: inline; 15 | padding-left: 5px; 16 | padding-right: 5px; 17 | } 18 | 19 | .site-wrapper { 20 | display: table; 21 | width: 100%; 22 | height: 100%; 23 | min-height: 100%; 24 | } 25 | 26 | .site-wrapper-inner { 27 | display: table-cell; 28 | vertical-align: middle; 29 | } 30 | 31 | .cover-container { 32 | margin-right: auto; 33 | margin-left: auto; 34 | width: 100%; 35 | } 36 | 37 | .footer { 38 | position: absolute; 39 | right: 0; 40 | bottom: 0; 41 | left: 0; 42 | padding: 2rem; 43 | text-align: center; 44 | } 45 | 46 | .btn { 47 | color: #C0C0C0; 48 | } -------------------------------------------------------------------------------- /cspy_rest_api/static/style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | background-color: #202020; 5 | font-family: Roboto, sans-serif; 6 | } 7 | 8 | body { 9 | color: #C0C0C0; 10 | text-align: center; 11 | } 12 | 13 | form { 14 | display: inline; 15 | padding-left: 5px; 16 | padding-right: 5px; 17 | } 18 | 19 | .site-wrapper { 20 | display: table; 21 | width: 100%; 22 | height: 100%; 23 | min-height: 100%; 24 | } 25 | 26 | .site-wrapper-inner { 27 | display: table-cell; 28 | vertical-align: middle; 29 | } 30 | 31 | .cover-container { 32 | margin-right: auto; 33 | margin-left: auto; 34 | width: 100%; 35 | } 36 | 37 | .footer { 38 | position: absolute; 39 | right: 0; 40 | bottom: 0; 41 | left: 0; 42 | padding: 2rem; 43 | text-align: center; 44 | } 45 | 46 | .btn { 47 | color: #C0C0C0; 48 | } -------------------------------------------------------------------------------- /cspy_client_app/src/setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from cx_Freeze import setup, Executable 3 | 4 | 5 | base = None 6 | if sys.platform == "win32": 7 | base = "Win32GUI" 8 | 9 | files = ['static/', 'templates/', 'gamestate_integration_main.cfg', 'run.py', '__init__.py', 'README.txt', 10 | 'VCRUNTIME140.dll'] 11 | 12 | cspy_exe = Executable(script="main.py", base=base, targetName="CS-Py.exe") 13 | 14 | setup(name="CS-Py", 15 | version="1.2", 16 | author="Parkkeo1", 17 | description="v1.2", 18 | options={ 19 | 'build_exe': { 20 | 'packages': ['jinja2.ext', 'jinja2', 'asyncio', 'numpy', 'pandas', 'sqlite3'], 21 | 'excludes': ['Tkinter', 'PyQt4', 'gtk', 'PyQt5', 'wx'], 22 | 'include_files': files, 23 | 'include_msvcr': True, 24 | }}, 25 | executables=[cspy_exe], requires=['flask'] 26 | ) 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Keon (Isaac) Park 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cspy_rest_api/src/user_data_payload.py: -------------------------------------------------------------------------------- 1 | class UserDataPayload: 2 | 3 | def __init__(self, payload): 4 | self.is_valid = False 5 | 6 | self.steamid = 0 7 | self.start = 0 8 | self.end = 0 9 | self.round_count = 0 10 | self.map_name = '' 11 | 12 | self.kills = 0 13 | self.assists = 0 14 | self.deaths = 0 15 | self.score = 0 16 | 17 | self.rating1 = 0 18 | self.hsr, self.ct_hsr, self.t_hsr = 0, 0, 0 19 | self.mdc, self.ct_mdc, self.t_mdc = 0, 0, 0 20 | self.kpr, self.ct_kpr, self.t_kpr = 0, 0, 0 21 | self.kas, self.ct_kas, self.t_kas = 0, 0, 0 22 | self.kdr, self.ct_kdr, self.t_kdr = 0, 0, 0 23 | self.kda, self.ct_kda, self.t_kda = 0, 0, 0 24 | self.mean_equip, self.ct_mean_equip, self.t_mean_equip = 0, 0, 0 25 | 26 | self.load_from_json(payload) 27 | 28 | def get_properties_list(self): 29 | return [x for x in dir(self) if not x.startswith('__') and x != 'is_valid' and not callable(getattr(self, x))] 30 | 31 | def load_from_json(self, payload): 32 | try: 33 | for prop in self.get_properties_list(): 34 | self.__setattr__(prop, payload[prop]) 35 | self.is_valid = True 36 | print("Valid Payload") 37 | except (ValueError, AttributeError, TypeError): 38 | self.is_valid = False 39 | print("Invalid Payload") 40 | -------------------------------------------------------------------------------- /cspy_rest_api/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CS-Py Remote Server 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

CS-Py RESTful API Server

17 |

A Personal Performance Analytics & Tracker Tool For CS:GO

18 |

Your match data is sent to and saved on this website.

19 | 23 |
24 |
25 |
26 | 27 | -------------------------------------------------------------------------------- /dev_testing/sample_json/alive_end_round.json: -------------------------------------------------------------------------------- 1 | {"map": {"current_spectators": 0, 2 | "mode": "competitive", 3 | "name": "de_cache", 4 | "num_matches_to_win_series": 0, 5 | "phase": "live", 6 | "round": 0, 7 | "souvenirs_total": 0, 8 | "team_ct": {"matches_won_this_series": 0, 9 | "score": 0, 10 | "timeouts_remaining": 1}, 11 | "team_t": {"matches_won_this_series": 0, 12 | "score": 0, 13 | "timeouts_remaining": 1}}, 14 | "player": {"activity": "playing", 15 | "match_stats": {"assists": 2, 16 | "deaths": 1, 17 | "kills": 3, 18 | "mvps": 0, 19 | "score": 2}, 20 | "name": "dumby", 21 | "observer_slot": 1, 22 | "state": {"armor": 0, 23 | "burning": 0, 24 | "equip_value": 850, 25 | "flashed": 0, 26 | "health": 100, 27 | "money": 450, 28 | "round_killhs": 1, 29 | "round_kills": 1, 30 | "smoked": 0}, 31 | "steamid": "76561198158189084", 32 | "team": "CT"}, 33 | "previously": {"round": {"phase": "live"}}, 34 | "provider": {"appid": 730, 35 | "name": "Counter-Strike: Global Offensive", 36 | "steamid": "76561198158189084", 37 | "timestamp": 1515881036, 38 | "version": 13622}, 39 | "round": {"phase": "over"}} -------------------------------------------------------------------------------- /dev_testing/sample_json/endgame_diff_player_data.json: -------------------------------------------------------------------------------- 1 | {"map": {"current_spectators": 0, 2 | "mode": "competitive", 3 | "name": "de_cache", 4 | "num_matches_to_win_series": 0, 5 | "phase": "gameover", 6 | "round": 0, 7 | "souvenirs_total": 0, 8 | "team_ct": {"matches_won_this_series": 0, 9 | "score": 0, 10 | "timeouts_remaining": 1}, 11 | "team_t": {"matches_won_this_series": 0, 12 | "score": 0, 13 | "timeouts_remaining": 1}}, 14 | "player": {"activity": "playing", 15 | "match_stats": {"assists": 2, 16 | "deaths": 1, 17 | "kills": 3, 18 | "mvps": 0, 19 | "score": 2}, 20 | "name": "dumby", 21 | "observer_slot": 1, 22 | "state": {"armor": 0, 23 | "burning": 0, 24 | "equip_value": 850, 25 | "flashed": 0, 26 | "health": 100, 27 | "money": 450, 28 | "round_killhs": 1, 29 | "round_kills": 1, 30 | "smoked": 0}, 31 | "steamid": "76561198158189085", 32 | "team": "CT"}, 33 | "previously": {"round": {"phase": "live"}}, 34 | "provider": {"appid": 730, 35 | "name": "Counter-Strike: Global Offensive", 36 | "steamid": "76561198158189084", 37 | "timestamp": 1515881035, 38 | "version": 13622}, 39 | "round": {"phase": "over"}} -------------------------------------------------------------------------------- /dev_testing/sample_json/dead_midround_data.json: -------------------------------------------------------------------------------- 1 | {"map": {"current_spectators": 0, 2 | "mode": "competitive", 3 | "name": "de_cache", 4 | "num_matches_to_win_series": 0, 5 | "phase": "live", 6 | "round": 0, 7 | "souvenirs_total": 0, 8 | "team_ct": {"matches_won_this_series": 0, 9 | "score": 0, 10 | "timeouts_remaining": 1}, 11 | "team_t": {"matches_won_this_series": 0, 12 | "score": 0, 13 | "timeouts_remaining": 1}}, 14 | "player": {"activity": "playing", 15 | "match_stats": {"assists": 2, 16 | "deaths": 2, 17 | "kills": 3, 18 | "mvps": 0, 19 | "score": 2}, 20 | "name": "dumby", 21 | "observer_slot": 1, 22 | "state": {"armor": 0, 23 | "burning": 0, 24 | "equip_value": 850, 25 | "flashed": 0, 26 | "health": 0, 27 | "money": 450, 28 | "round_killhs": 1, 29 | "round_kills": 1, 30 | "smoked": 0}, 31 | "steamid": "76561198158189084", 32 | "team": "CT"}, 33 | "previously": {"player": {"match_stats": {"deaths": 1}, 34 | "state": {"armor": 68, "health": 31}}}, 35 | "provider": {"appid": 730, 36 | "name": "Counter-Strike: Global Offensive", 37 | "steamid": "76561198158189084", 38 | "timestamp": 1515881038, 39 | "version": 13622}, 40 | "round": {"bomb": "planted", "phase": "live"}} -------------------------------------------------------------------------------- /dev_testing/sample_json/invalid_data.json: -------------------------------------------------------------------------------- 1 | {"map": {"current_spectators": 0, 2 | "mode": "competitive", 3 | "name": "de_cache", 4 | "num_matches_to_win_series": 0, 5 | "phase": "live", 6 | "round": 0, 7 | "souvenirs_total": 0, 8 | "team_ct": {"matches_won_this_series": 0, 9 | "score": 0, 10 | "timeouts_remaining": 1}, 11 | "team_t": {"matches_won_this_series": 0, 12 | "score": 0, 13 | "timeouts_remaining": 1}}, 14 | "player": {"activity": "playing", 15 | "match_stats": {"assists": 2, 16 | "deaths": 2, 17 | "kills": 3, 18 | "mvps": 0, 19 | "score": 2}, 20 | "name": "dumby", 21 | "observer_slot": 1, 22 | "state": {"armor": 0, 23 | "burning": 0, 24 | "equip_value": 850, 25 | "flashed": 0, 26 | "health": 100, 27 | "money": 450, 28 | "round_killhs": 1, 29 | "round_kills": 1, 30 | "smoked": 0}, 31 | "steamid": "76561198158189084", 32 | "team": "CT"}, 33 | "previously": {"player": {"match_stats": {"deaths": 1}, 34 | "state": {"armor": 68, "health": 31}}}, 35 | "provider": {"appid": 730, 36 | "name": "Counter-Strike: Global Offensive", 37 | "steamid": "76561198158189084", 38 | "timestamp": 1515881037, 39 | "version": 13622}, 40 | "round": {"bomb": "planted", "phase": "live"}} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # My own ignores 2 | .idea/ 3 | legacy/ 4 | 5 | # Byte-compiled / optimized / DLL files 6 | __pycache__/ 7 | *.py[cod] 8 | *$py.class 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | env/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | installers/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # dotenv 88 | .env 89 | 90 | # virtualenv 91 | .venv 92 | venv/ 93 | ENV/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | -------------------------------------------------------------------------------- /cspy_client_app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CS-Py For CS:GO 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |

CS-Py

17 |

A Personal Performance Analytics & Tracker Tool For CS:GO

18 |
19 |
20 | 21 |
22 |
23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 36 |
37 |

{{ status }}

38 |
39 |
40 | 41 | -------------------------------------------------------------------------------- /docs/stats.md: -------------------------------------------------------------------------------- 1 | ## Understanding CS-Py's Statistics 2 | 3 | As a program that tracks players' performance in CS:GO, CS-Py generates a variety of metrics about and for the user. 4 | Thus, it is necessary to provide explanations on how these numbers are calculated so that players are able to better gauge their in-game skill. The statistics below are what CS-Py collects and stores into a remote database. 5 | 6 | ### The Statistics (* in More Details Section) 7 | 8 | 1. User's Unique Steam ID 9 | 2. Start/End UNIX Timestamps for Match 10 | 3. Number of Rounds in Match 11 | 4. Match Map 12 | 5. Kills, Assists, Deaths 13 | 6. Score (Same as In-game) 14 | 7. HLTV Rating v1.0 15 | 16 | #### NOTE: Metrics 8-13 Are Recorded For Both, CT, and T Sides. 17 | 18 | 8. Headshot Ratio*- The ratio of your kills that end in a headshot (like the in-game killfeed) 19 | 9. Monetary Dependency Ratio* 20 | 10. Kills Per Round* 21 | 11. KAS Percentage* 22 | 12. Kill-Death Ratio (KDR), Kill-Assist-Death Ratio (KDA)* 23 | 13. Mean Equipment Value* 24 | 25 | ### More Details 26 | 27 | #### Headshot Ratio (HSR) 28 | The ratio of your kills that end in a headshot (like the in-game killfeed) 29 | 30 | 31 | #### Monetary Dependency Correlation Coefficient (MD Correlation) 32 | The correlation between how many kills you get in each round and your equipment value in that given round. 33 | 34 | This stat is useful for calculating whether a player tends to need better weapons/equipment to play much better (i.e. player relies on having an AWP or a full nadeset to be good) or do as well with all types of low and high tier equipment. 35 | 36 | 37 | #### Kills Per Round (KPR) 38 | How many kills you get per round, on average. Calculated with: total number of kills / total number of rounds played. 39 | 40 | 41 | #### KAS Percentage 42 | Modified version of the KAST statistic by HLTV. CS-Py excludes traded deaths. From HLTV: 43 | > You also may have noticed the addition of KAST (percentage of rounds with a kill, assist, survival or traded death) to our site last month, which is a stat that is best described as round-to-round consistency. It helps us notice players who might not put up the big numbers but often contribute to their team in some fashion. 44 | 45 | 46 | #### Kill (+ Assist) / Death Ratio (KDR and KDA) 47 | Self-explanatory. Calculated with: total number of kills (+ total number of assists) / total number of deaths. 48 | 49 | In a team game like CS:GO, KDA is more useful. 50 | 51 | 52 | #### Mean Equipment Value 53 | In dollars, your average equipment value (value of your guns, armor, etc) in the given timeframe (match, day, week, etc). 54 | 55 | Shows whether you were able to comfortably full-buy for most of your game(s) or you were constantly eco-ing or force-buying. 56 | -------------------------------------------------------------------------------- /dev_testing/script_samples.py: -------------------------------------------------------------------------------- 1 | # standalone helper script, used for testing 2 | 3 | import sys 4 | import json 5 | import requests 6 | import sqlite3 7 | from pprint import pprint 8 | import pandas as pd 9 | 10 | # # testing with round_data json file instead of match_data 11 | # with open('dead_midround_data.json') as json_file: 12 | # data = json.load(json_file) 13 | # 14 | # # backup 15 | # # data2 = {'steamid': 76561198158189084, 'start': 1515881036, 'end': 1515881038, 'round_count': 2, 'map_name': 'de_cache', 'rating1': 0, 'ct_rating1': 0, 't_rating1': 0, 'hsr': 1.0, 'ct_hsr': 1.0, 't_hsr': 0, 'mdc': 0, 'ct_mdc': 0, 't_mdc': 0, 'kpr': 1.0, 'ct_kpr': 1.0, 't_kpr': 0, 'kas': 0, 'ct_kas': 0, 't_kas': 0, 'kdr': 1.5, 'ct_kdr': 1.5, 't_kdr': 0, 'kda': 2.5, 'ct_kda': 2.5, 't_kda': 0, 'mean_equip': 850, 'ct_mean_equip': 850, 't_mean_equip': 0} 16 | # 17 | # round_db = sqlite3.connect('../cspy_client_app/rounds_data.db') 18 | # data_for_match_df = pd.read_sql('SELECT * FROM per_round_data;', round_db) 19 | # 20 | # match_data = MatchAnalysis(data_for_match_df) 21 | # del match_data.data_frame 22 | # print(match_data.__dict__) 23 | 24 | # sys.stdout = open('testing_log.txt', 'a') 25 | # print('\n') 26 | # 27 | # # valid user 1 28 | # r1 = requests.get('http://127.0.0.1:5001/api/user_data/76561198268849559') 29 | # pprint(r1.json()) 30 | # 31 | # # valid user 2 32 | # r2 = requests.get('http://127.0.0.1:5001/api/user_data/76561198158189084') 33 | # pprint(r2.json()) 34 | # 35 | # # invalid user 36 | # r3 = requests.get('http://127.0.0.1:5001/api/user_data/12345') 37 | # pprint(r3.json()) 38 | 39 | d = json.loads('{"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361906}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "gameover", "round": 26, "team_ct": {"score": 15, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT", "bomb": "defused"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4550, "round_kills": 2, "round_killhs": 0, "equip_value": 3550}, "match_stats": {"kills": 29, "assists": 8, "deaths": 16, "mvps": 6, "score": 79}}, "previously": {"map": {"phase": "live", "round": 25}, "round": {"phase": "live", "bomb": "planted"}, "player": {"observer_slot": 5, "state": {"money": 750}, "match_stats": {"mvps": 5, "score": 77}}}, "added": {"round": {"win_team": true}}}') 40 | r = requests.post('http://127.0.0.1:5000/GS', json=d) 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /required_user_files/README.txt: -------------------------------------------------------------------------------- 1 | CS-Py Installation/Usage Instructions: 2 | 3 | NOTE: CS-Py uses Valve's Game-State Integration (used by tournaments for custom HUDS and by Plays.tv for overlays), 4 | so using it is fine/legal (and ethical, since it doesn't give you an in-game advantage). 5 | 6 | 1. Run install_cspy.exe. Follow the instructions on the installer. 7 | 8 | 2. After installation, run CS-Py.exe as administrator. 9 | 10 | 3. Check to make sure gamestate_integration_main.cfg is in your csgo/cfg directory. 11 | More detailed instructions: http://bit.ly/2D32JSu (Valve Developer Website/Wiki) 12 | 13 | NOTE: CS-Py automatically copies the cfg file into your csgo directory, but you should still check to make sure. 14 | 15 | 4. When the browser opens: 16 | a. If this is your first time, then the player database must be created first. 17 | - Press the 'Start GS' button and play a competitive game, preferably a standard matchmaking game. 18 | - During the game, you can examine your current stats for the match by choosing 'Current Match' to analyze. 19 | - After the game, you can examine your past game stats by choosing 'Past Match' to analyze. 20 | - Other analyze options are available: day, week, month, lifetime. 21 | - Press 'Stop' to stop gathering data. Do this when you arent actively playing a competitive match. 22 | - Make sure 'GS is currently ON' before your MM/competitive match starts. 23 | 24 | b. If you have already recorded data previously with the program, you can immediately analyze your stats after starting CS-Py. You can also choose to do the above and collect data while playing a match. 25 | 26 | NOTE: CS-Py only collects 'competitive' mode games/matches. Deathmatch and Casual, for example, are automatically ignored. 27 | 28 | 5. Important details: 29 | a. The 'Reset Match' button is for when you exit a match early (i.e. retake server) and want to start a new game (i.e. MM). 30 | Resetting the match makes sure your stats from different games/servers don't get accidentally combined/convoluted. 31 | 32 | b. Due to how CS:GO handles bot games, the pistol rounds statistics will be incorrect if data is collected for an bot match. 33 | However, other statistics will still be accurate. 34 | 35 | c. The statistics calculated and data collected by CS-Py has been verified to be correct for MM matches. 36 | Due to how ESEA Pugs restart the match multiple times before going live, results may vary. 37 | 38 | d. This program can record and calculate your performance statistics for matches while GS is enabled. 39 | Thus, it does not work for games that you play(ed) without having this program running and enabled. 40 | 41 | 6. Report bugs here: https://github.com/Parkkeo1/CS-Py/issues 42 | 43 | 7. Further documentation for CS-Py can be found at: https://github.com/Parkkeo1/CS-Py 44 | 45 | Created by Parkkeo1/LGIC 46 | -------------------------------------------------------------------------------- /cspy_rest_api/src/flask_api_server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sqlite3 3 | 4 | from flask import Flask, request, render_template 5 | from flask_restful import Resource, Api 6 | from flask_cors import CORS 7 | 8 | from sql_db_manager import does_user_exist, add_new_user, update_existing_user, is_duplicate_match, insert_match_data, \ 9 | server_sql_setup, load_matches_from_sql 10 | from user_data_payload import UserDataPayload 11 | 12 | cs_py_server = Flask(__name__, template_folder='../templates', static_folder='../static') 13 | cors = CORS(cs_py_server, resources={r'/api/user_data/*': {'origins': '*'}}) 14 | 15 | cs_py_rest_api = Api(cs_py_server) 16 | cs_py_server.config['DATABASE'] = os.path.join(cs_py_server.root_path, '..', 'users_and_matches.db') 17 | 18 | # --------------------------- 19 | 20 | 21 | # Frontend routes 22 | 23 | @cs_py_server.route('/', methods=['GET']) 24 | def index(): 25 | return render_template('index.html') 26 | 27 | 28 | @cs_py_server.after_request 29 | def add_header(response): 30 | response.headers['Cache-Control'] = 'public, max-age=0' 31 | return response 32 | 33 | # --------------------------- 34 | 35 | # API classes and functions 36 | 37 | 38 | # for the future frontend website/web app on EWS for CS-Py that will display to users their results 39 | class FrontEndDataApi(Resource): 40 | def get(self, user_steamid): 41 | sql_db = sqlite3.connect(cs_py_server.config['DATABASE']) 42 | 43 | if does_user_exist(user_steamid, sql_db): 44 | # format is a list of dictionaries 45 | all_user_matches = load_matches_from_sql(int(user_steamid), sql_db) 46 | sql_db.close() 47 | return all_user_matches 48 | else: 49 | sql_db.close() 50 | return 'User Has No Saved Matches', 404 51 | 52 | 53 | # for receiving match data from user clients 54 | class ReceiveDataApi(Resource): 55 | def post(self): 56 | if request.is_json: 57 | print(request.get_json()) 58 | payload = UserDataPayload(request.get_json()) 59 | 60 | if payload.is_valid: 61 | sql_db = sqlite3.connect(cs_py_server.config['DATABASE']) 62 | 63 | if does_user_exist(payload.steamid, sql_db): # user already exists 64 | if not is_duplicate_match(payload, sql_db): 65 | insert_match_data(payload, sql_db) 66 | update_existing_user(payload.steamid, sql_db) 67 | 68 | else: # user does not exist 69 | insert_match_data(payload, sql_db) 70 | add_new_user(payload.steamid, sql_db) 71 | 72 | sql_db.close() 73 | return 'Data Accepted', 202 74 | 75 | return 'Invalid Data', 400 76 | 77 | 78 | cs_py_rest_api.add_resource(ReceiveDataApi, '/api/data_receiver') 79 | cs_py_rest_api.add_resource(FrontEndDataApi, '/api/user_data/') 80 | 81 | # TODO For deployment, use PythonAnywhere. 82 | if __name__ == '__main__': 83 | server_sql_setup(sqlite3.connect(cs_py_server.config['DATABASE'])) 84 | # cs_py_server.run(debug=False, port=5001) 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CS-Py (WIP v2) 2 | A performance analytics tool for CS:GO that analyzes players' data to provide deep insights into their skill through detailed metrics such as consistency, accuracy, and impact per game (ex. HLTV Rating, KAS %, HSR). Features a Python-Flask & SQL local client and remote RESTful API server. By Isaac Park, CS Major @ UIUC. 3 | 4 | **Project Status:** v2 is WIP; it will feature a local Flask client and a remote Flask RESTful API Server. I also plan to develop a React.js frontend website to display the match results to the user. The RESTful API server will provide the website with the data. 5 | 6 | ### Why and How 7 | For a game meant for competitive play, Counter-Strike: Global Offensive surprisingly lacks built-in options by which players can analyze their own performance. In standard match-making, the in-game scoreboard only displays simple statistics (kills, assists, deaths, score, and the number of round "MVPs") that, while useful for cursory glances during the game, are inadequate metrics to accurately gauge player skill. **Edit**: Even after the new Panorama update, certain detailed statistics are missing in the default game. 8 | 9 | Existing third-party websites such as csgo-stats.com seem to mostly provide overly general (total kills, total games played, etc) and often outdated data about players. Most of these website services require users to manually download their demo replay files from the CS:GO client and upload them. Along with this inconvenience, demo files are known to often be corrupted. HLTV.org, while very solid in terms of data and analysis, only keeps track of professional players and matches. 10 | 11 | Thus, CS-Py's purpose, as an user & web application, is to expand the number of metrics available to normal players and provide more indicative and accurate analyses of their performance in CS:GO. 12 | 13 | CS-Py is made possible by CS:GO's developer feature: [Game-State Integration](https://developer.valvesoftware.com/wiki/Counter-Strike:_Global_Offensive_Game_State_Integration). JSON payloads containing real-time game data are rapidly sent (every 1-2 seconds) by the CS:GO client and are processed/analyzed for player performance. The calculated metrics and results are stored in a SQLite database and then sent to the remote REST API. I plan to implement a separate front-end web app, probably with React.js and Express.js, that will use the data from the API to display the analysis results to users. 14 | 15 | ### Project Objectives for v2 16 | 1. Overhaul client Flask user application to be object-oriented, efficient, and cleaner in terms of code design. Improved SQL design. 17 | 2. Implement new Flask RESTful API server and deploy on PythonAnywhere. This server will store match analysis results for all users. 18 | 3. Implement new React.js frontend website that will use the RESTful API to get analysis results and display to the user. 19 | 20 | ### v1.1 Released. Install CS-Py [Here](https://github.com/Parkkeo1/CS-Py/releases/tag/v1.1) For Windows. 21 | - **Note**: v1 is the old release; CS-Py is a standalone, local Flask application and not a client-server web app. 22 | - Current statistical features of CS-Py are explained [here.](https://github.com/Parkkeo1/CS-Py/blob/master/docs/stats.md) 23 | - Please report bugs by creating a new issue [here.](https://github.com/Parkkeo1/CS-Py/issues) 24 | -------------------------------------------------------------------------------- /cspy_client_app/src/game_state_payload.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class GameStateCode(Enum): 5 | INVALID = -1 6 | ENDGAME_DIFF_PLAYER = 0 7 | ALIVE_END_ROUND = 1 8 | DEAD_MID_ROUND = 2 9 | 10 | 11 | class GameStatePayload: 12 | 13 | def __init__(self, payload): 14 | self.__dict__ = payload 15 | self.load_nested_data() 16 | self.gamestate_code = self.classify_payload() 17 | 18 | def get_properties_list(self): 19 | return [x for x in dir(self) if not x.startswith('__') and not callable(getattr(self, x))] 20 | 21 | def load_nested_data(self): 22 | for prop in self.get_properties_list(): 23 | if type(self.__getattribute__(prop)) is dict: 24 | subsection = GameStatePayload(self.__getattribute__(prop)) 25 | self.__setattr__(prop, subsection) 26 | subsection.load_nested_data() 27 | 28 | # KEY PROPERTIES PROPERTIES FOR CHECKS 29 | # 30 | # provider.timestamp player.activity 31 | # map.name map.mode 32 | # map.phase map.round 33 | # player.name provider.steamid 34 | # player.team player.steamid 35 | # player.match_stats round.phase 36 | # player.state previously.player.state 37 | # previously.round.phase 38 | 39 | # check the existence of key properties (provider, player, map, etc) 40 | def basic_check(self): 41 | try: 42 | print(self.provider.timestamp, self.map.name, self.map.phase, self.player.name, self.player.team, 43 | self.player.match_stats, self.player.state, self.map.team_ct.score, self.map.team_t.score) 44 | print(self.player.activity, self.map.mode, self.map.round, self.provider.steamid, self.player.steamid, 45 | self.round.phase) 46 | return True 47 | except (TypeError, AttributeError, ValueError): 48 | return False 49 | 50 | valid_map_phases = {'live', 'intermission', 'gameover'} 51 | 52 | # check which category of payload this is 53 | def classify_payload(self): 54 | if not self.basic_check(): 55 | return GameStateCode.INVALID 56 | elif self.player.activity == 'playing' and self.map.mode == 'competitive': 57 | if self.map.phase in GameStatePayload.valid_map_phases: 58 | 59 | if self.provider.steamid == self.player.steamid: # if player is alive (not an observer at time of payload) 60 | if self.round.phase == 'over': # end-of-round, player is alive 61 | try: 62 | return GameStateCode.ALIVE_END_ROUND if self.previously.round.phase == 'live' else GameStateCode.INVALID 63 | 64 | except (TypeError, AttributeError, ValueError): 65 | return GameStateCode.INVALID 66 | elif self.round.phase == 'live' and self.player.state.health == 0: # mid-round, player dies 67 | try: 68 | return GameStateCode.DEAD_MID_ROUND if self.previously.player.state.health > 0 else GameStateCode.INVALID 69 | 70 | except (TypeError, AttributeError, ValueError): 71 | return GameStateCode.INVALID 72 | else: 73 | if self.map.phase == 'gameover' and self.round.phase == 'over': # end-game 74 | try: 75 | return GameStateCode.ENDGAME_DIFF_PLAYER if self.previously.round.phase == 'live' else GameStateCode.INVALID 76 | 77 | except (TypeError, AttributeError, ValueError): 78 | return GameStateCode.INVALID 79 | 80 | return GameStateCode.INVALID 81 | -------------------------------------------------------------------------------- /cspy_client_app/src/flask_user_app.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import json 3 | import os 4 | import shutil 5 | import sqlite3 6 | import sys 7 | import webbrowser 8 | import winreg 9 | 10 | from flask import Flask, request, render_template, g, redirect, url_for 11 | 12 | from game_state_payload import GameStateCode, GameStatePayload 13 | from sql_data_processing import init_table_if_not_exists, check_prev_entries, insert_round_data, send_match_to_remote 14 | 15 | # string constants 16 | GS_CFG_DEST_PATH = '/steamapps/common/Counter-Strike Global Offensive/csgo/cfg/gamestate_integration_main.cfg' 17 | GS_CFG_SRC_PATH = '../../required_user_files/gamestate_integration_main.cfg' 18 | GS_ON = 'GS is currently ON' 19 | GS_OFF = 'GS is currently OFF' 20 | 21 | # Web address of RESTful API server to which match data is sent 22 | API_ADDRESS = 'http://Parkkeo1.pythonanywhere.com/api/data_receiver' 23 | 24 | # the CS-Py Flask object 25 | cs_py_client = Flask(__name__, template_folder='../templates', static_folder='../static') 26 | cs_py_client.config['DATABASE'] = os.path.join(cs_py_client.root_path, '..', 'rounds_data.db') 27 | cs_py_client.config['STATE'] = False 28 | 29 | 30 | # --------------------------- 31 | 32 | # database connection handling 33 | def get_db(): 34 | if not hasattr(g, 'sqlite_db'): 35 | g.sqlite_db = sqlite3.connect(cs_py_client.config['DATABASE']) 36 | return g.sqlite_db 37 | 38 | 39 | @cs_py_client.teardown_appcontext 40 | def close_db(error): 41 | if hasattr(g, 'sqlite_db'): 42 | g.sqlite_db.close() 43 | 44 | 45 | # --------------------------- 46 | 47 | # manual shutdown method 48 | # derived from: http://flask.pocoo.org/snippets/67/ 49 | def shutdown_server(): 50 | quit_cspy = request.environ.get('werkzeug.server.shutdown') 51 | if quit_cspy is None: 52 | raise RuntimeError('Flask Server Not Running') 53 | quit_cspy() 54 | 55 | 56 | # --------------------------- 57 | 58 | def setup_gamestate_cfg(): 59 | try: 60 | steam_key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "Software\Valve\Steam") 61 | cfg_destination = winreg.QueryValueEx(steam_key, "SteamPath")[0] + GS_CFG_DEST_PATH 62 | shutil.copyfile(GS_CFG_SRC_PATH, cfg_destination) 63 | # print('Auto CFG File Passed') 64 | except (OSError, shutil.SameFileError): 65 | # print('Auto CFG File Failed') 66 | return 67 | 68 | # --------------------------- 69 | 70 | 71 | # flask server routes 72 | 73 | # the home page, handles frontend user interaction 74 | @cs_py_client.route('/', methods=['GET', 'POST']) 75 | def index(): 76 | if request.method == 'POST': 77 | user_input = str(request.form.get('input')) 78 | 79 | # user chooses to start or end active data collection 80 | if user_input == 'start': 81 | cs_py_client.config['STATE'] = True 82 | 83 | elif user_input == 'stop': 84 | cs_py_client.config['STATE'] = False 85 | 86 | # user chooses to reset, ending collection for current match 87 | elif user_input == 'reset': 88 | send_match_to_remote(get_db(), API_ADDRESS) 89 | 90 | return redirect(url_for('index')) 91 | 92 | else: 93 | # updating frontend status of CS-Py 94 | status = GS_ON if cs_py_client.config['STATE'] else GS_OFF 95 | return render_template('index.html', status=status) 96 | 97 | 98 | # route that receives JSON payloads from the game client 99 | # noinspection PyTypeChecker 100 | @cs_py_client.route('/GS', methods=['POST']) 101 | def gamestate_handler(): 102 | if request.is_json and cs_py_client.config['STATE']: 103 | round_db = get_db() 104 | game_data = GameStatePayload(copy.deepcopy(request.get_json())) 105 | json_log = open('../logs/rounds_json.txt', 'a') 106 | 107 | if game_data.gamestate_code == GameStateCode.INVALID: 108 | round_db.close() 109 | json_log.close() 110 | return 'Invalid Data Received' 111 | elif game_data.gamestate_code == GameStateCode.ENDGAME_DIFF_PLAYER: 112 | json_log.write('----\n\n') 113 | 114 | send_match_to_remote(round_db, API_ADDRESS) 115 | else: 116 | if check_prev_entries(game_data, round_db): # checks for duplicate entries. 117 | # saving raw json of accepted data to file 118 | json_log.write(json.dumps(request.get_json())) 119 | json_log.write('\n\n') 120 | 121 | insert_round_data(game_data, round_db) 122 | if game_data.map.phase == 'gameover': # automatic reset if player was alive by end of game. 123 | json_log.write('----\n\n') 124 | 125 | send_match_to_remote(round_db, API_ADDRESS) 126 | round_db.close() 127 | json_log.close() 128 | return 'Request Received' 129 | return 'GS is OFF or non-JSON Received' 130 | 131 | 132 | @cs_py_client.route('/shutdown', methods=['POST']) 133 | def shutdown(): 134 | shutdown_server() 135 | return 'CS-Py is shutting down. You may now close this browser window/tab.' 136 | 137 | 138 | @cs_py_client.after_request 139 | def add_header(response): 140 | response.headers['Cache-Control'] = 'public, max-age=0' 141 | return response 142 | 143 | 144 | if __name__ == "__main__": 145 | # setup 146 | sql_db = sqlite3.connect(cs_py_client.config['DATABASE']) 147 | init_table_if_not_exists(sql_db) 148 | setup_gamestate_cfg() 149 | 150 | # auto-opens browser window to CS-Py frontend 151 | webbrowser.open_new('http://127.0.0.1:5000') 152 | cs_py_client.run(debug=False, threaded=True) 153 | -------------------------------------------------------------------------------- /cspy_rest_api/src/sql_db_manager.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | pd.set_option('display.max_rows', 500) 4 | pd.set_option('display.max_columns', 500) 5 | pd.set_option('display.width', 1000) 6 | 7 | # --------------------------- 8 | 9 | # Functions for handling POST requests 10 | 11 | 12 | # makes sure required tables exist; if not, create them 13 | def server_sql_setup(sql_db): 14 | create_users_table_sql = '''CREATE TABLE IF NOT EXISTS all_users (User_SteamID INTEGER, "Match Count" INTEGER)''' 15 | 16 | create_matches_table_sql = '''CREATE TABLE IF NOT EXISTS all_matches (Match_ID INTEGER PRIMARY KEY, 17 | User_SteamID INTEGER, Start INTEGER, End INTEGER, 18 | 'Round Count' INTEGER, Map TEXT, Kills INTEGER, 19 | Assists INTEGER, Deaths INTEGER, Score INTEGER, 20 | Rating1 REAL, HSR REAL, MDC REAL, KPR REAL, KAS REAL, 21 | KDR REAL, KDA REAL, MEAN REAL, 22 | CT_HSR REAL, CT_MDC REAL, 23 | CT_KPR REAL, CT_KAS REAL, CT_KDR REAL, 24 | CT_KDA REAL, CT_MEAN REAL, 25 | T_HSR REAL, T_MDC REAL, T_KPR REAL, T_KAS REAL, 26 | T_KDR REAL, T_KDA REAL, T_MEAN REAL, 27 | FOREIGN KEY (User_SteamID) 28 | REFERENCES all_users(User_SteamID))''' 29 | 30 | db_cursor = sql_db.cursor() 31 | db_cursor.execute(create_users_table_sql) 32 | db_cursor.execute(create_matches_table_sql) 33 | sql_db.commit() 34 | print("SQL Table Check Passed") 35 | 36 | 37 | # returns True if user already exists in database, False if user is not yet in DB. 38 | def does_user_exist(payload_user_id, sql_db): 39 | all_users_cursor = sql_db.cursor() 40 | 41 | check_for_user_sql = '''SELECT EXISTS (SELECT 1 FROM all_users WHERE User_SteamID == ?)''' 42 | all_users_cursor.execute(check_for_user_sql, (payload_user_id,)) 43 | 44 | if all_users_cursor.fetchone() == (0,): 45 | print("New User") 46 | return False 47 | else: 48 | print("Existing User") 49 | return True 50 | 51 | 52 | # adds new user and initializes the match count to 1 53 | def add_new_user(user_id, sql_db): 54 | all_users_cursor = sql_db.cursor() 55 | 56 | add_user_sql = '''INSERT INTO all_users(User_SteamID, "Match Count") VALUES (?, ?)''' 57 | all_users_cursor.execute(add_user_sql, (user_id, 1)) 58 | sql_db.commit() 59 | print("New User: %s Added" % user_id) 60 | 61 | 62 | # adds 1 to the match count of user in the all_users sql table 63 | def update_existing_user(user_id, sql_db): 64 | all_users_cursor = sql_db.cursor() 65 | 66 | update_user_sql = '''UPDATE all_users SET "Match Count" = "Match Count" + 1 WHERE User_SteamID == ?''' 67 | all_users_cursor.execute(update_user_sql, (user_id,)) 68 | sql_db.commit() 69 | print("Match Count of User: %s Updated" % user_id) 70 | 71 | 72 | # checks for duplicate matches in the all_matches table with current payload, using user_id, start, and end times 73 | # Returns True if duplicate exists. False if payload is unique, new entry. 74 | def is_duplicate_match(payload, sql_db): 75 | all_matches_cursor = sql_db.cursor() 76 | 77 | # if there's at least one that matches the current payload, then duplicate exists. 78 | check_for_duplicate_sql = '''SELECT EXISTS (SELECT 1 from all_matches WHERE User_SteamID == ? AND Start == ? AND End == ?)''' 79 | all_matches_cursor.execute(check_for_duplicate_sql, (payload.steamid, payload.start, payload.end)) 80 | 81 | if all_matches_cursor.fetchone() == (0,): 82 | print("Not A Duplicate, Inserting") 83 | return False 84 | else: 85 | print("Duplicate Found, Not Inserting") 86 | return True 87 | 88 | 89 | # inserts user data into all_matches SQL table 90 | def insert_match_data(payload, sql_db): 91 | all_matches_cursor = sql_db.cursor() 92 | 93 | insert_user_data_sql = '''INSERT INTO all_matches(User_SteamID, Start, End, 'Round Count', Map, Kills, Assists, 94 | Deaths, Score, Rating1, HSR, MDC, 95 | KPR, KAS, KDR, KDA, MEAN, CT_HSR, CT_MDC, CT_KPR, CT_KAS, CT_KDR, 96 | CT_KDA, CT_MEAN, T_HSR, T_MDC, T_KPR, T_KAS, T_KDR, T_KDA, T_MEAN) 97 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 98 | ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''' 99 | 100 | new_match_data = ( 101 | payload.steamid, payload.start, payload.end, payload.round_count, payload.map_name, payload.kills, 102 | payload.assists, payload.deaths, payload.score, payload.rating1, 103 | payload.hsr, payload.mdc, payload.kpr, payload.kas, payload.kdr, payload.kda, payload.mean_equip, payload.ct_hsr, 104 | payload.ct_mdc, payload.ct_kpr, payload.ct_kas, payload.ct_kdr, payload.ct_kda, payload.ct_mean_equip, payload.t_hsr, 105 | payload.t_mdc, payload.t_kpr, payload.t_kas, payload.t_kdr, payload.t_kda, payload.t_mean_equip 106 | ) 107 | 108 | all_matches_cursor.execute(insert_user_data_sql, new_match_data) 109 | sql_db.commit() 110 | print("New Match Data Inserted For User: %s" % payload.steamid) 111 | 112 | 113 | # --------------------------- 114 | 115 | # Functions for handling GET requests 116 | 117 | 118 | # Gets matches of given user as SQL query, loads data into Pandas dataframe, then returns dataframe as list of dicts. 119 | def load_matches_from_sql(user_steam_id, sql_db): 120 | get_user_matches_sql = '''SELECT * from all_matches WHERE User_SteamID == ?''' 121 | user_matches_df = pd.read_sql(get_user_matches_sql, sql_db, params=(user_steam_id,)) 122 | user_matches_list = user_matches_df.to_dict(orient='records') 123 | return user_matches_list 124 | -------------------------------------------------------------------------------- /cspy_rest_api/all_data.txt: -------------------------------------------------------------------------------- 1 | User_SteamID Match Count 2 | 0 76561198158189084 11 3 | 1 76561198268849559 14 4 | 5 | 6 | Match_ID User_SteamID Start End Round Count Map Kills Assists Deaths Score Rating1 HSR MDC KPR KAS KDR KDA MEAN CT_HSR CT_MDC CT_KPR CT_KAS CT_KDR CT_KDA CT_MEAN T_HSR T_MDC T_KPR T_KAS T_KDR T_KDA T_MEAN 7 | 0 1 76561198158189084 1530749022 1530751490 30 de_train 17 6 22 43 0.80 0.471 0.093 0.57 63.0 0.773 1.045 4092.0 0.500 0.197 0.67 67.0 0.773 1.045 4337.0 0.429 -0.122 0.47 60.0 0.583 1.000 3847.0 8 | 1 2 76561198158189084 1530824960 1530827310 28 de_cache 19 7 19 53 0.92 0.211 0.151 0.68 75.0 1.000 1.368 4220.0 0.286 -0.241 0.47 60.0 0.538 0.846 2927.0 0.167 0.094 0.92 92.0 1.000 1.368 5712.0 9 | 2 3 76561198158189084 1530858399 1530860473 22 de_overpass 19 4 13 45 1.26 0.368 0.310 0.86 68.0 1.462 1.769 3934.0 0.286 0.385 1.00 71.0 1.462 1.769 3329.0 0.417 0.333 0.80 67.0 1.714 1.857 4217.0 10 | 3 4 76561198268849559 1530904432 1530907202 30 de_overpass 29 4 19 70 1.56 0.414 -0.031 0.97 77.0 1.526 1.737 4325.0 0.500 -0.153 0.80 80.0 1.333 1.444 4613.0 0.353 0.131 1.13 80.0 1.526 1.737 4037.0 11 | 4 5 76561198268849559 1530910847 1530913454 30 de_train 35 4 15 85 1.80 0.371 -0.007 1.17 77.0 2.333 2.600 4930.0 0.316 0.041 1.27 80.0 2.375 2.875 5197.0 0.438 -0.092 1.07 73.0 2.333 2.600 4663.0 12 | 5 6 76561198268849559 1530914424 1530917006 29 de_mirage 21 4 22 47 1.06 0.286 0.505 0.72 52.0 0.955 1.136 3781.0 0.083 0.359 0.80 53.0 1.091 1.364 3877.0 0.556 0.740 0.64 57.0 0.955 1.136 3679.0 13 | 6 7 76561198158189084 1530937745 1530940311 28 de_overpass 21 2 19 52 1.04 0.100 0.202 0.71 54.0 1.105 1.211 4177.0 0.143 0.283 0.54 54.0 1.105 1.211 3919.0 0.077 0.078 0.87 60.0 1.625 1.750 4400.0 14 | 7 8 76561198268849559 1530993649 1530995988 21 de_cbble 31 4 12 68 2.26 0.355 0.366 1.48 76.0 2.583 2.917 4745.0 0.294 0.511 1.31 62.0 2.429 2.714 5219.0 0.429 0.236 1.75 100.0 2.583 2.917 3975.0 15 | 8 9 76561198268849559 1530996277 1530997496 17 de_train 24 2 8 53 2.25 0.375 0.491 1.41 88.0 3.000 3.250 5026.0 0.375 0.332 1.60 100.0 4.000 4.333 5413.0 0.000 0.000 0.00 50.0 3.000 3.250 2125.0 16 | 9 10 76561198268849559 1531033426 1531034786 18 de_overpass 19 1 6 39 1.85 0.368 -0.255 1.06 94.0 3.167 3.333 5142.0 0.375 -0.322 1.07 100.0 3.200 3.200 5603.0 0.333 -0.317 1.00 67.0 3.167 3.333 2833.0 17 | 10 11 76561198268849559 1531115280 1531116880 23 de_cache 21 4 12 52 1.46 0.429 0.178 0.91 70.0 1.750 2.083 4557.0 0.429 0.187 0.93 67.0 1.556 1.889 4463.0 0.429 0.169 0.88 75.0 2.333 2.667 4731.0 18 | 11 12 76561198158189084 1531182198 1531185115 30 de_overpass 31 4 20 80 1.42 0.323 0.376 1.03 80.0 1.550 1.750 4312.0 0.286 0.534 0.93 73.0 1.167 1.250 3753.0 0.353 0.146 1.13 87.0 2.125 2.500 4870.0 19 | 12 13 76561198268849559 1531193773 1531196760 29 de_overpass 30 2 19 67 1.44 0.300 0.023 1.03 79.0 1.579 1.684 4652.0 0.222 -0.137 1.20 93.0 1.800 1.900 4727.0 0.417 0.210 0.86 64.0 1.333 1.444 4571.0 20 | 13 14 76561198268849559 1531197100 1531199903 29 de_inferno 35 4 18 78 1.78 0.441 0.095 1.17 79.0 1.944 2.167 4286.0 0.412 0.073 1.13 87.0 2.429 2.714 4593.0 0.471 0.140 1.21 71.0 1.636 1.818 3957.0 21 | 14 15 76561198268849559 1531281726 1531283820 23 de_cbble 19 1 15 49 1.31 0.400 0.463 0.87 61.0 1.267 1.333 4524.0 0.500 0.338 1.25 88.0 2.500 2.750 5300.0 0.300 0.495 0.67 47.0 0.818 0.818 4110.0 22 | 15 16 76561198268849559 1531284268 1531286439 24 de_cache 27 5 10 67 1.97 0.407 -0.059 1.12 83.0 2.700 3.200 4965.0 0.400 -0.441 1.00 80.0 2.143 2.571 4987.0 0.417 0.436 1.33 89.0 4.000 4.667 4928.0 23 | 16 17 76561198158189084 1531372179 1531375031 29 de_overpass 22 4 17 64 1.15 0.591 0.033 0.76 66.0 1.294 1.529 4302.0 0.800 0.007 0.77 54.0 1.000 1.300 4173.0 0.417 0.067 0.75 75.0 1.714 1.857 4406.0 24 | 17 18 76561198158189084 1531461051 1531463686 29 de_cache 24 4 21 67 1.25 0.520 0.293 0.86 69.0 1.143 1.333 3857.0 0.400 0.327 1.07 71.0 1.667 1.889 4525.0 0.700 0.098 0.67 67.0 0.750 0.917 3233.0 25 | 18 19 76561198158189084 1531613124 1531615445 24 de_cache 24 1 18 57 1.57 0.417 0.179 1.00 50.0 1.333 1.389 3312.0 0.462 0.259 0.87 40.0 1.182 1.273 2953.0 0.364 -0.077 1.22 67.0 1.571 1.571 3911.0 26 | 19 20 76561198158189084 1531621458 1531623727 25 de_mirage 18 3 17 44 1.16 0.444 0.096 0.72 64.0 1.059 1.235 3782.0 0.364 -0.034 0.79 64.0 1.000 1.182 3689.0 0.571 0.309 0.64 64.0 1.167 1.333 3900.0 27 | 20 21 76561198268849559 1531799834 1531801913 24 de_overpass 32 0 11 69 2.15 0.469 0.083 1.33 79.0 2.909 2.909 4710.0 0.500 0.131 1.47 80.0 2.444 2.444 4787.0 0.400 -0.065 1.11 78.0 5.000 5.000 4583.0 28 | 21 22 76561198158189084 1534284740 1534287783 32 de_inferno 22 3 21 48 0.99 0.500 0.144 0.75 69.0 1.048 1.190 3702.0 0.500 0.201 0.53 60.0 0.727 0.909 3523.0 0.500 0.059 0.94 76.0 1.400 1.500 3859.0 29 | 22 23 76561198158189084 1534297573 1534300158 29 de_train 8 2 26 20 0.33 0.375 0.029 0.28 38.0 0.308 0.385 3438.0 0.400 0.098 0.33 40.0 0.333 0.400 3277.0 0.333 -0.048 0.21 36.0 0.273 0.364 3611.0 30 | 23 24 76561198268849559 1534359227 1534361906 26 de_overpass 29 8 16 79 1.67 0.483 0.334 1.12 73.0 1.812 2.312 4069.0 0.500 0.659 0.73 64.0 1.000 1.625 3332.0 0.476 0.036 1.40 80.0 2.625 3.000 4610.0 31 | -------------------------------------------------------------------------------- /cspy_client_app/src/match_analysis.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | class MatchAnalysis: 5 | 6 | # Formula Constants 7 | HLTV_KPR_CONST = 0.658 8 | HLTV_SURVIVAL_CONST = 0.318 9 | HLTV_MULTIKILL_CONST = 1.193 10 | HLTV_DIVIDE_CONST = 2.7 11 | 12 | def __init__(self, round_data_df): 13 | self.data_frame = round_data_df 14 | 15 | # simple properties 16 | self.steamid = int(self.data_frame['SteamID'].iloc[-1]) # to keep track of user when sending match data to remote. 17 | self.start = int(self.data_frame['Time'].iloc[0]) 18 | self.end = int(self.data_frame['Time'].iloc[-1]) 19 | self.round_count = self.data_frame.shape[0] 20 | self.map_name = self.data_frame['Map'].iloc[-1] 21 | 22 | # overall stats 23 | self.kills = int(self.data_frame['Kills'].iloc[-1]) 24 | self.assists = int(self.data_frame['Assists'].iloc[-1]) 25 | self.deaths = int(self.data_frame['Deaths'].iloc[-1]) 26 | self.score = int(self.data_frame['Score'].iloc[-1]) 27 | 28 | # to-be calculated properties 29 | self.rating1 = 0 30 | self.hsr, self.ct_hsr, self.t_hsr = 0, 0, 0 31 | self.mdc, self.ct_mdc, self.t_mdc = 0, 0, 0 32 | self.kpr, self.ct_kpr, self.t_kpr = 0, 0, 0 33 | self.kas, self.ct_kas, self.t_kas = 0, 0, 0 34 | self.kdr, self.ct_kdr, self.t_kdr = 0, 0, 0 35 | self.kda, self.ct_kda, self.t_kda = 0, 0, 0 36 | self.mean_equip, self.ct_mean_equip, self.t_mean_equip = 0, 0, 0 37 | 38 | # Function to calculate all performance metrics 39 | self.calculate_main() 40 | 41 | def calculate_main(self): 42 | first_team = self.data_frame['Player Team'].iloc[0] 43 | 44 | ct_data = self.data_frame[self.data_frame['Player Team'] == 'CT'] 45 | t_data = self.data_frame[self.data_frame['Player Team'] == 'T'] 46 | 47 | # HSR: Headshot Ratio 48 | # MDC: Monetary Dependency Coefficient 49 | # KPR: Kills Per Round 50 | # KDR, KDA: Kill Death Ratio, Kill+Assist Death Ratio 51 | # MEAN: Mean Equipment Value 52 | 53 | # Totals 54 | if not self.data_frame.empty: 55 | self.rating1 = self.calculate_rating(self.data_frame) 56 | self.hsr = self.calculate_hsr(self.data_frame) 57 | self.mdc = self.calculate_mdc(self.data_frame) 58 | self.kpr = self.calculate_kpr(self.data_frame) 59 | self.kas = self.calculate_kas(self.data_frame, 0, 0, 0) 60 | self.kdr, self.kda = self.calculate_kdr_kda(self.data_frame, 0, 0, 0) 61 | self.mean_equip = int(round(self.data_frame['Current Equip. Value'].mean(skipna=True))) 62 | 63 | # CT 64 | if not ct_data.empty: 65 | self.ct_hsr = self.calculate_hsr(ct_data) 66 | self.ct_mdc = self.calculate_mdc(ct_data) 67 | self.ct_kpr = self.calculate_kpr(ct_data) 68 | 69 | if first_team == 'CT': 70 | self.ct_kas = self.calculate_kas(ct_data, 0, 0, 0) 71 | self.ct_kdr, self.ct_kda = self.calculate_kdr_kda(ct_data, 0, 0, 0) 72 | else: 73 | self.ct_kas = self.calculate_kas(ct_data, t_data['Kills'].iloc[-1], t_data['Assists'].iloc[-1], 74 | t_data['Deaths'].iloc[-1]) 75 | self.ct_kdr, self.ct_kda = self.calculate_kdr_kda(ct_data, t_data['Kills'].iloc[-1], 76 | t_data['Assists'].iloc[-1], t_data['Deaths'].iloc[-1]) 77 | 78 | self.ct_mean_equip = int(round(ct_data['Current Equip. Value'].mean(skipna=True))) 79 | 80 | # T 81 | if not t_data.empty: 82 | self.t_hsr = self.calculate_hsr(t_data) 83 | self.t_mdc = self.calculate_mdc(t_data) 84 | self.t_kpr = self.calculate_kpr(t_data) 85 | 86 | if first_team == 'T': 87 | self.t_kas = self.calculate_kas(t_data, 0, 0, 0) 88 | self.t_kdr, self.t_kda = self.calculate_kdr_kda(t_data, 0, 0, 0) 89 | else: 90 | self.t_kas = self.calculate_kas(t_data, ct_data['Kills'].iloc[-1], ct_data['Assists'].iloc[-1], 91 | ct_data['Deaths'].iloc[-1]) 92 | self.t_kdr, self.t_kda = self.calculate_kdr_kda(t_data, ct_data['Kills'].iloc[-1], 93 | ct_data['Assists'].iloc[-1], ct_data['Deaths'].iloc[-1]) 94 | 95 | self.t_mean_equip = int(round(t_data['Current Equip. Value'].mean(skipna=True))) 96 | 97 | def calculate_rating(self, relevant_data_df): 98 | # HLTV's Kill Rating Formula 99 | kill_rating = self.calculate_kpr(relevant_data_df) / MatchAnalysis.HLTV_KPR_CONST 100 | 101 | total_rounds = relevant_data_df.shape[0] 102 | # HLTV's Survival Rating Formula 103 | survival_rating = ((total_rounds - relevant_data_df['Deaths'].iloc[-1]) / total_rounds) / MatchAnalysis.HLTV_SURVIVAL_CONST 104 | 105 | multikill_rounds = [0, 0, 0, 0, 0, 0] 106 | 107 | for i in range(total_rounds): 108 | multikill_rounds[int(relevant_data_df['Round Kills'].iloc[i])] += 1 109 | 110 | # HLTV's MultiKill Rating Formula 111 | multikill_rating = ((multikill_rounds[1] + 112 | (4 * multikill_rounds[2]) + 113 | (9 * multikill_rounds[3]) + 114 | (16 * multikill_rounds[4]) + 115 | (25 * multikill_rounds[5])) / total_rounds) / MatchAnalysis.HLTV_MULTIKILL_CONST 116 | 117 | # HLTV's Rating 1.0 Formula 118 | combined_rating = (kill_rating + (0.7 * survival_rating) + multikill_rating) / MatchAnalysis.HLTV_DIVIDE_CONST 119 | return float(round(combined_rating, 2)) 120 | 121 | @staticmethod 122 | def calculate_hsr(relevant_data_df): 123 | total_kills = relevant_data_df['Round Kills'].sum(skipna=True) 124 | total_hs_kills = relevant_data_df['Round HS Kills'].sum(skipna=True) 125 | 126 | if total_kills == 0 or total_hs_kills == 0: 127 | return 0 128 | else: 129 | return float(round(total_hs_kills / total_kills, 3)) 130 | 131 | @staticmethod 132 | def calculate_mdc(relevant_data_df): 133 | mdc_coeff = float(round(relevant_data_df['Round Kills'].corr(relevant_data_df['Current Equip. Value']), 3)) 134 | return mdc_coeff if not math.isnan(mdc_coeff) else 0 135 | 136 | @staticmethod 137 | def calculate_kpr(relevant_data_df): 138 | total_kills = relevant_data_df['Round Kills'].sum(skipna=True) 139 | total_rounds = relevant_data_df.shape[0] 140 | 141 | if total_kills == 0 or total_rounds == 0: 142 | return 0 143 | else: 144 | return float(round(total_kills / total_rounds, 2)) 145 | 146 | @staticmethod 147 | def calculate_kas(relevant_data_df, prev_kill_count, prev_assist_count, prev_death_count): 148 | kas_count = 0 149 | 150 | # Check rest of rounds 151 | for i in range(0, relevant_data_df.shape[0]): 152 | if relevant_data_df['Round Kills'].iloc[i] > 0 or \ 153 | relevant_data_df['Kills'].iloc[i] > prev_kill_count or \ 154 | relevant_data_df['Assists'].iloc[i] > prev_assist_count or \ 155 | relevant_data_df['Deaths'].iloc[i] == prev_death_count: 156 | kas_count += 1 157 | 158 | prev_kill_count = relevant_data_df['Kills'].iloc[i] 159 | prev_assist_count = relevant_data_df['Assists'].iloc[i] 160 | prev_death_count = relevant_data_df['Deaths'].iloc[i] 161 | 162 | if kas_count == 0: 163 | return 0 164 | 165 | return round(kas_count / relevant_data_df.shape[0], 2) * 100 166 | 167 | @staticmethod 168 | def calculate_kdr_kda(relevant_data_df, prev_side_kills, prev_side_assists, prev_side_deaths): 169 | last_entry = relevant_data_df.iloc[-1] 170 | 171 | kill_total = last_entry['Kills'] - prev_side_kills 172 | assist_total = last_entry['Assists'] - prev_side_assists 173 | death_total = last_entry['Deaths'] - prev_side_deaths 174 | 175 | kdr = float(round(kill_total / death_total, 3)) 176 | kda = float(round((kill_total + assist_total) / death_total, 3)) 177 | return kdr, kda 178 | -------------------------------------------------------------------------------- /cspy_client_app/src/sql_data_processing.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import time 3 | 4 | import pandas as pd 5 | 6 | from match_analysis import MatchAnalysis 7 | 8 | # utility methods for processing in flask routes 9 | 10 | 11 | def init_table_if_not_exists(sql_db): 12 | create_round_table_sql = '''CREATE TABLE IF NOT EXISTS per_round_data (Time INTEGER, SteamID INTEGER, Map TEXT, 13 | 'Map Status' TEXT, Round INTEGER, 'GS Code' INTEGER, 14 | CT_Score INTEGER, T_Score INTEGER, 'Player Name' TEXT, 15 | 'Player Team' TEXT, Kills INTEGER, Assists INTEGER, 16 | Deaths INTEGER, MVPs INTEGER, Score INTEGER, 17 | 'Current Equip. Value' INTEGER, 'Round Kills' INTEGER, 18 | 'Round HS Kills' INTEGER);''' 19 | 20 | sql_db.cursor().execute(create_round_table_sql) 21 | sql_db.commit() 22 | 23 | 24 | # checks previous entries in database to make sure there are no duplicates. 25 | def check_prev_entries(game_data, round_db): 26 | 27 | def is_endround_duplicate(last_entry_row, payload): 28 | match_stats = payload.player.match_stats 29 | player_state = payload.player.state 30 | 31 | if player_state.round_kills > 0 and last_entry_row['Kills'] == match_stats.kills: 32 | return True 33 | 34 | # assists cause duplicates (+1 to assists in the second entry while everything else is same) 35 | return last_entry_row['Player Team'] == payload.player.team and \ 36 | last_entry_row['CT_Score'] == payload.map.team_ct.score and \ 37 | last_entry_row['T_Score'] == payload.map.team_t.score and \ 38 | last_entry_row['Kills'] == match_stats.kills and \ 39 | last_entry_row['Deaths'] == match_stats.deaths and \ 40 | last_entry_row['Round Kills'] == player_state.round_kills and \ 41 | last_entry_row['Round HS Kills'] == player_state.round_killhs 42 | 43 | # TODO: Tentative 44 | # for when player supposedly died midround for two rounds in a row. 45 | def is_midround_duplicate(last_entry_row, payload): 46 | match_stats = payload.player.match_stats 47 | player_state = payload.player.state 48 | 49 | if player_state.round_kills > 0 and last_entry_row['Kills'] == match_stats.kills: 50 | return True 51 | 52 | # if 2->2, then deaths must be different. 53 | if match_stats.deaths == last_entry_row['Deaths']: 54 | return True 55 | 56 | # forgot to return False!!! 57 | return False 58 | 59 | # TODO: temp removal in favor of deaths simple count check 60 | # # includes assists check 61 | # # can check deaths == deaths because for GS codes == 2 two in a row, must have died. 62 | # # checks round # because same round # entries seem to only occur with a GS code pattern of 1, 2. 63 | # first_pass = last_entry_row['Player Team'] == payload.player.team and \ 64 | # last_entry_row['Kills'] == match_stats.kills and \ 65 | # last_entry_row['Assists'] == match_stats.assists and \ 66 | # last_entry_row['Deaths'] == match_stats.deaths and \ 67 | # last_entry_row['Round Kills'] == player_state.round_kills and \ 68 | # last_entry_row['Round HS Kills'] == player_state.round_killhs 69 | # 70 | # # excludes assists check, instead includes equip. value check 71 | # second_pass = last_entry_row['Player Team'] == payload.player.team and \ 72 | # last_entry_row['Kills'] == match_stats.kills and \ 73 | # last_entry_row['Deaths'] == match_stats.deaths and \ 74 | # last_entry_row['Round Kills'] == player_state.round_kills and \ 75 | # last_entry_row['Round HS Kills'] == player_state.round_killhs and \ 76 | # last_entry_row['CT_Score'] == payload.map.team_ct.score and \ 77 | # last_entry_row['T_Score'] == payload.map.team_t.score and \ 78 | # last_entry_row['Current Equip. Value'] == player_state.equip_value 79 | # 80 | # return True if first_pass or second_pass else False 81 | 82 | server_log = open('../logs/server_log.txt', 'a') 83 | last_entry = pd.read_sql('SELECT * FROM per_round_data ORDER BY Time DESC LIMIT 1;', round_db) 84 | 85 | if last_entry.shape[0] != 0: 86 | if abs(int(game_data.provider.timestamp - last_entry.iloc[0]['Time'])) <= 1: 87 | sql_delete = 'DELETE FROM per_round_data WHERE Time = (SELECT MAX(Time) FROM per_round_data);' 88 | round_db.cursor().execute(sql_delete) 89 | round_db.commit() 90 | server_log.write('Time Duplicate Replaced\n') 91 | server_log.close() 92 | return True 93 | 94 | # 2->1 95 | if game_data.gamestate_code.value == 1: # Checking for duplicate combo of midround death + endround payloads 96 | if last_entry.iloc[0]['GS Code'] == 2: 97 | if is_endround_duplicate(last_entry.iloc[0], game_data): 98 | server_log.write('Round Duplicate Not Inserted\n') 99 | server_log.close() 100 | return False # do not insert a duplicate. 101 | 102 | # 2->2 103 | if game_data.gamestate_code.value == 2: 104 | if last_entry.iloc[0]['GS Code'] == 2: 105 | # TODO: Tentative 106 | if is_midround_duplicate(last_entry.iloc[0], game_data): 107 | server_log.write('Round Duplicate Not Inserted\n') 108 | server_log.close() 109 | return False # do not insert a duplicate. 110 | 111 | server_log.close() 112 | return True 113 | 114 | 115 | def insert_round_data(round_data, round_db): 116 | match_stats = round_data.player.match_stats 117 | player_state = round_data.player.state 118 | 119 | new_round_data = ( 120 | round_data.provider.timestamp, round_data.provider.steamid, round_data.map.name, round_data.map.phase, 121 | round_data.map.round, round_data.gamestate_code.value, round_data.map.team_ct.score, 122 | round_data.map.team_t.score, 123 | round_data.player.name, round_data.player.team, match_stats.kills, match_stats.assists, match_stats.deaths, 124 | match_stats.mvps, match_stats.score, player_state.equip_value, player_state.round_kills, 125 | player_state.round_killhs) 126 | 127 | round_insert_sql = ''' INSERT INTO per_round_data(Time, SteamID, Map, "Map Status", Round, 'GS Code', CT_Score, T_Score, 128 | "Player Name", "Player Team", Kills, Assists, Deaths, MVPs, Score, 129 | "Current Equip. Value", "Round Kills", "Round HS Kills") 130 | VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' 131 | round_db.cursor().execute(round_insert_sql, new_round_data) 132 | round_db.commit() 133 | 134 | 135 | # clears per_round_data table to indicate end of game 136 | def send_match_to_remote(round_db, api_address): 137 | server_log = open('../logs/server_log.txt', 'a') 138 | 139 | # parse current per_round_data into dataframe 140 | data_for_match_df = pd.read_sql('SELECT * FROM per_round_data;', round_db) 141 | if data_for_match_df.empty or data_for_match_df.shape[0] == 0: 142 | server_log.close() 143 | return # cancel if there's no data to analyze or send 144 | 145 | match_data = MatchAnalysis(data_for_match_df) 146 | del match_data.data_frame 147 | req_success = False 148 | 149 | for i in range(3): 150 | time.sleep(2) 151 | try: 152 | send_match_request = requests.post(api_address, json=match_data.__dict__, timeout=5) 153 | if send_match_request.status_code == 202: 154 | req_success = True 155 | break 156 | except requests.exceptions.RequestException as e: 157 | server_log.write('Requests Exception: %s\n' % e) 158 | 159 | # checking if request was successful 160 | if req_success: # CS-Py's API should send 202: Accepted as response code upon success. 161 | # TODO: Temporarily removing auto-wipe of round_data table 162 | # clear per_round_data table 163 | # round_db.cursor().execute('DELETE FROM per_round_data;') 164 | # round_db.commit() 165 | server_log.write('Match Data Sent; Rounds Reset\n---\n\n') 166 | else: 167 | server_log.write('API Request Failed. Not Clearing Round Data\n--\n\n') 168 | server_log.close() 169 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | ### Changelog 2 | 12/22/17: Switch to Flask successful (I think). Will be implementing SQLite3 DB functionality instead of using Flask-Session. TODO: put 3 | received data into pandas dataframe, then insert dataframe contents into sql table. Create DB file. 4 | 5 | 12/23/17: Previous day's goals accomplished; POST data is put into pandas dataframes and then inserted into SQLite DB tables accordingly: per_round_data and per_map_data. Also made some preliminary frontend changes to set up for the todo. TODO: Work on front-end; auto-refreshing display page for live match stats? Maybe also work on statistical analysis & visualizations using the ideas above. 6 | 7 | 12/24/17: Continued to work on front-end. Flask app now can receive 1 of 5 possible, different inputs from the user (last match, today, past 7 days, past month, lifetime). TODO: work on creating a query_db function that queries the database table differently depending on user request. 8 | 9 | 12/25/17: Today was more testing, gathering data, and refining collection methods. Fixed some data collection bugs by editing check_payload. Also edited DB structure and implemented a clean_db function to remove accidental duplicate data from the SQL table. Decided to delete the per_map_data SQL table; unnecessary. Same TODO as yesterday: work on creating a query_db function that queries the database table differently depending on user request. 10 | 11 | 12/26/17: Changed Data collection approach: changed 'Time' column back to the default UNIX Timestamps and added a 'gameover' event entry to make it easier to sort by individual matches. Tests for these changes were successful. Also worked on a simple HSR calculation function to call in the various query_db functions. Query_db functions return a 'result' dictionary back to the flask main.py. Basic test to display the calculated HSR for the past 24 hours onto the front-end was successful. TODO: keep working on the query_db functions. 12 | 13 | 12/26/17 (More): WIP start and end data collection functionality/options available to the user (to make sure the user can start collecting performance data for actual matches, not warmup or retake mode games). Using app.config because the default session module did not carry over to GSHandler. Updated front-end. TODO: work on query_db functions and create a helper function to determine entries where map status == 'gameover', in order to pinpoint individual match data. 14 | 15 | 12/27/17: Collected 2 matches worth of data, with the 'gameover' event entries to mark the end of matches. Finished and successfully tested query_db_match and query_db_time methods. Will be gathering more data later and testing further to make sure each timeframe analysis works. Also fixed some bugs where some flask variable strings/names were mismatched to those in the HTML templates. TODO: create helper function to separate matches and calculate KDR/KDA/KAS functions. 16 | 17 | 12/28/17: README.md overhaul. Fixed the clean_db() function to ignore the 'Time' column in the dataframe. Added 'Current Match' option and its function, query_db_current, for analyzing current, live match. TODO: work on separate() and kdr/kda/kas functions. 18 | 19 | 12/28/17 (More): Finished separate() and worked on kdr_kda() in database.py. Separate() returns a list of dataframes (that are chunks of the original dataframe). Have to work on making sure that correct "original" dataframes are fed into the separate and kdr_kda functions when calculating statistics for the various time filters (i.e. make sure to not feed in the entire SQL table for all of them). TODO: Finish kdr_kda, test separate() and kdr_kda(). 20 | 21 | 12/29/17: Finished and successfully tested kdr_kda(), which uses separate() to determine KADs for each match. Tested with verified correct KDR/KDA values for different time queries. Fixed bug where if no entries have been added recently (i.e. past 24 hours), a corresponding query would raise a NaN to int conversion error. Now, zeroes are returned instead of NaN floats. TODO: front-end button to allow the user to "reset" the current match status (i.e. create a blank 'gameover' entry to manually create a new "current" game). Also start working on the KAS ratio function. 22 | 23 | 12/30/17: Finished and manually verified results for kas(). Separate() again came in handy for kas(). Fixed bug where if the only entry in the past 24 hours is a reset point, it would crash with the same error as yesterday. Now, if all of the entries in the past ___ time frame are only NaN/None values, it just returns zeroes. Main.py now checks, on 'Reset Match' button press, whether the last entry in the SQL table was also a reset point (i.e. is a new reset point really necesary?). Implemented front-end button for 'reset match'. TODO: start developing the graph-based analytics (w/ probably something simple like matplotlib) and further test the program in all aspects by gathering more data. 24 | 25 | 12/30/17 (More): While working on matplotlib/graph-analysis functionality, I ran into a bug: an indexerror was raised for the 'past 24 hours' query because for some reason, an if statement that used .iloc[-1] was not being recognized as a valid index value for a dataframe in df_list. Although I have fixed this issue for now by implementing a reset_index whenever separate() is called, I plan to write more possible fixes in case it happens again. Even though I believe .iloc[-1] should be calling the last row of match_df, regardless of .index (match_df ranges from 82-88 when .index is called at the time I am writing this), it still raises an indexerror. 26 | 27 | 12/31/17: Still using reset_index as a fix; other attempted fixes did not work. Without reset_index, df_list had an empty dataframe 28 | in it that was causing index errors in kdr_kda and kas. I also made a remove_empty df function from df_list in case reset_index fix does not work for other edge cases. Also, fixed error where flask was not automatically updating matplotlib images unless user manually refreshed the page. Fixed this using app.after_request and setting cache life to zero. TODO: make sure the graph function returns a blank image when an invalid query is done (i.e. no matches have been played since last match, no matches in past 24 hours, etc) 29 | 30 | 12/31/17 (More): More data was collected and successfully tested with. Fixed bug where if there were two 'gameover' entries adjacent to each other in the table and the latter was an endgame or reset point entry the program would crash because it would try to calculate statistics using either 1) an empty df or 2) a df that only had null values. This was fixed by manually deleting the adjacent 'gameover' entries using database.py and preventing it from happening again in the future. Now, whenever GSHandler processes an endgame entry, it checks to make sure the current last entry in the SQL table isn't also a 'gameover' entry before inserting the endgame one. TODO: More testing, gathering data, and working on graph functions (especially for returning blank image when invalid query). 31 | 32 | 1/1/18. Lots of edits and commits. Created abstraction/wrapper function for calculating all of the statistics. Added the blank graph function. Gathered more player data and tested program with it sucessfully. Added kpr (kills per round) function. Started working on front-end nav tabs for the 3 diff. stats tables: overall, ct, t. TODO: create functions to calculate CT/T side statistics, edit front-end accordingly, and start analyzing pistol rounds. Also, more graphs would be good. 33 | 34 | 1/2/18: Finished and successfully tested pistol round statistics. Also re-verified the results of kas and kpr functions by manually comparing the statistics with the in-game demo for yesterday's de_cbble game. Edited front-end to accomodate new overall, ct, t tabs and pistol stats for each of them. Worked on some statistics documentation/explanations. TODO: Polish and add new things to documentation. Come up with better ideas for graphs. Get more data and verify program's results. 35 | 36 | 1/4/18-1/5/18: Fixed some bugs where program would not work if there was little data to calculate with. Implemented cx_Freeze to create executable/installable windows program for CS-Py. Tested successfully with 3 different computers/tests. Wrote docs for installation instructions. Test .msi installer released as v0.1-beta. TODO: Further test CS-Py.exe and maybe do more graphs. Eventually move on to full-screen overlay? Also improve SQL database/table layout and structure. 37 | 38 | 1/6/18-1/7/18: Focused more on making CS-Py into an installable windows program/executable with cx_Freeze, distutils, and Inno Setup. Made CS-Py.exe and the installer executable automatically require admin permissions. More testing to be done, but so far successful. Running CS-Py as admin is required because the program has to constantly access and create/edit the SQL db file. Also temporarily removed matplotlib and graph functionality, considering switching to a more lightweight and simple graphing library. TODO: Do more testing with the program and find a better graphing package. 39 | 40 | 1/8/18: Released v0.3-beta. Focused on reducing the program's file size by excluding unnecessary modules in setup.py. Added and successfully tested mpld3 for matplotlib; now using direct HTML embedding using Jinja instead of using .png image files. TODO: Make more graphs, and keep testing v0.3-beta. 41 | 42 | 1/11/18: Released v1.0. Tested successfully. TODO: keep testing to further ensure program's accuracy in calculating user statistics. 43 | 44 | 1/12/18: WIP fixing edge case issue where two entries are inserted into the table for one round due to nearly instantaneous traded deaths that end the round/match while the player is still in the death animation/cycle. Two methods to test to fix this issue. 45 | 46 | 1/13/18-1/14/18: More testing. Released v1.1 but seems game state is now sending strings instead of int values for the categories that were being sent as ints up until a day or two ago. Added ensure_types() and edited parse_payload() to make sure the types are appropriately changed. TODO: Test this fix with more playing data, recompile and re-release v1.1, and check if game state is actually returning string data. 47 | -------------------------------------------------------------------------------- /dev_testing/testing_log.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | [{'Assists': 4, 4 | 'CT_HSR': 0.5, 5 | 'CT_KAS': 80.0, 6 | 'CT_KDA': 1.444, 7 | 'CT_KDR': 1.333, 8 | 'CT_KPR': 0.8, 9 | 'CT_MDC': -0.153, 10 | 'CT_MEAN': 4613.0, 11 | 'Deaths': 19, 12 | 'End': 1530907202, 13 | 'HSR': 0.414, 14 | 'KAS': 77.0, 15 | 'KDA': 1.737, 16 | 'KDR': 1.526, 17 | 'KPR': 0.97, 18 | 'Kills': 29, 19 | 'MDC': -0.031, 20 | 'MEAN': 4325.0, 21 | 'Map': 'de_overpass', 22 | 'Match_ID': 4, 23 | 'Rating1': 1.56, 24 | 'Round Count': 30, 25 | 'Score': 70, 26 | 'Start': 1530904432, 27 | 'T_HSR': 0.353, 28 | 'T_KAS': 80.0, 29 | 'T_KDA': 1.737, 30 | 'T_KDR': 1.526, 31 | 'T_KPR': 1.13, 32 | 'T_MDC': 0.131, 33 | 'T_MEAN': 4037.0, 34 | 'User_SteamID': 76561198268849559}, 35 | {'Assists': 4, 36 | 'CT_HSR': 0.316, 37 | 'CT_KAS': 80.0, 38 | 'CT_KDA': 2.875, 39 | 'CT_KDR': 2.375, 40 | 'CT_KPR': 1.27, 41 | 'CT_MDC': 0.041, 42 | 'CT_MEAN': 5197.0, 43 | 'Deaths': 15, 44 | 'End': 1530913454, 45 | 'HSR': 0.371, 46 | 'KAS': 77.0, 47 | 'KDA': 2.6, 48 | 'KDR': 2.333, 49 | 'KPR': 1.17, 50 | 'Kills': 35, 51 | 'MDC': -0.007, 52 | 'MEAN': 4930.0, 53 | 'Map': 'de_train', 54 | 'Match_ID': 5, 55 | 'Rating1': 1.8, 56 | 'Round Count': 30, 57 | 'Score': 85, 58 | 'Start': 1530910847, 59 | 'T_HSR': 0.438, 60 | 'T_KAS': 73.0, 61 | 'T_KDA': 2.6, 62 | 'T_KDR': 2.333, 63 | 'T_KPR': 1.07, 64 | 'T_MDC': -0.092, 65 | 'T_MEAN': 4663.0, 66 | 'User_SteamID': 76561198268849559}, 67 | {'Assists': 4, 68 | 'CT_HSR': 0.083, 69 | 'CT_KAS': 53.0, 70 | 'CT_KDA': 1.364, 71 | 'CT_KDR': 1.091, 72 | 'CT_KPR': 0.8, 73 | 'CT_MDC': 0.359, 74 | 'CT_MEAN': 3877.0, 75 | 'Deaths': 22, 76 | 'End': 1530917006, 77 | 'HSR': 0.286, 78 | 'KAS': 52.0, 79 | 'KDA': 1.136, 80 | 'KDR': 0.955, 81 | 'KPR': 0.72, 82 | 'Kills': 21, 83 | 'MDC': 0.505, 84 | 'MEAN': 3781.0, 85 | 'Map': 'de_mirage', 86 | 'Match_ID': 6, 87 | 'Rating1': 1.06, 88 | 'Round Count': 29, 89 | 'Score': 47, 90 | 'Start': 1530914424, 91 | 'T_HSR': 0.556, 92 | 'T_KAS': 56.99999999999999, 93 | 'T_KDA': 1.136, 94 | 'T_KDR': 0.955, 95 | 'T_KPR': 0.64, 96 | 'T_MDC': 0.74, 97 | 'T_MEAN': 3679.0, 98 | 'User_SteamID': 76561198268849559}, 99 | {'Assists': 4, 100 | 'CT_HSR': 0.294, 101 | 'CT_KAS': 62.0, 102 | 'CT_KDA': 2.714, 103 | 'CT_KDR': 2.429, 104 | 'CT_KPR': 1.31, 105 | 'CT_MDC': 0.511, 106 | 'CT_MEAN': 5219.0, 107 | 'Deaths': 12, 108 | 'End': 1530995988, 109 | 'HSR': 0.355, 110 | 'KAS': 76.0, 111 | 'KDA': 2.917, 112 | 'KDR': 2.583, 113 | 'KPR': 1.48, 114 | 'Kills': 31, 115 | 'MDC': 0.366, 116 | 'MEAN': 4745.0, 117 | 'Map': 'de_cbble', 118 | 'Match_ID': 8, 119 | 'Rating1': 2.26, 120 | 'Round Count': 21, 121 | 'Score': 68, 122 | 'Start': 1530993649, 123 | 'T_HSR': 0.429, 124 | 'T_KAS': 100.0, 125 | 'T_KDA': 2.917, 126 | 'T_KDR': 2.583, 127 | 'T_KPR': 1.75, 128 | 'T_MDC': 0.236, 129 | 'T_MEAN': 3975.0, 130 | 'User_SteamID': 76561198268849559}, 131 | {'Assists': 2, 132 | 'CT_HSR': 0.375, 133 | 'CT_KAS': 100.0, 134 | 'CT_KDA': 4.333, 135 | 'CT_KDR': 4.0, 136 | 'CT_KPR': 1.6, 137 | 'CT_MDC': 0.332, 138 | 'CT_MEAN': 5413.0, 139 | 'Deaths': 8, 140 | 'End': 1530997496, 141 | 'HSR': 0.375, 142 | 'KAS': 88.0, 143 | 'KDA': 3.25, 144 | 'KDR': 3.0, 145 | 'KPR': 1.41, 146 | 'Kills': 24, 147 | 'MDC': 0.491, 148 | 'MEAN': 5026.0, 149 | 'Map': 'de_train', 150 | 'Match_ID': 9, 151 | 'Rating1': 2.25, 152 | 'Round Count': 17, 153 | 'Score': 53, 154 | 'Start': 1530996277, 155 | 'T_HSR': 0.0, 156 | 'T_KAS': 50.0, 157 | 'T_KDA': 3.25, 158 | 'T_KDR': 3.0, 159 | 'T_KPR': 0.0, 160 | 'T_MDC': 0.0, 161 | 'T_MEAN': 2125.0, 162 | 'User_SteamID': 76561198268849559}, 163 | {'Assists': 1, 164 | 'CT_HSR': 0.375, 165 | 'CT_KAS': 100.0, 166 | 'CT_KDA': 3.2, 167 | 'CT_KDR': 3.2, 168 | 'CT_KPR': 1.07, 169 | 'CT_MDC': -0.322, 170 | 'CT_MEAN': 5603.0, 171 | 'Deaths': 6, 172 | 'End': 1531034786, 173 | 'HSR': 0.368, 174 | 'KAS': 94.0, 175 | 'KDA': 3.333, 176 | 'KDR': 3.167, 177 | 'KPR': 1.06, 178 | 'Kills': 19, 179 | 'MDC': -0.255, 180 | 'MEAN': 5142.0, 181 | 'Map': 'de_overpass', 182 | 'Match_ID': 10, 183 | 'Rating1': 1.85, 184 | 'Round Count': 18, 185 | 'Score': 39, 186 | 'Start': 1531033426, 187 | 'T_HSR': 0.333, 188 | 'T_KAS': 67.0, 189 | 'T_KDA': 3.333, 190 | 'T_KDR': 3.167, 191 | 'T_KPR': 1.0, 192 | 'T_MDC': -0.317, 193 | 'T_MEAN': 2833.0, 194 | 'User_SteamID': 76561198268849559}, 195 | {'Assists': 4, 196 | 'CT_HSR': 0.429, 197 | 'CT_KAS': 67.0, 198 | 'CT_KDA': 1.889, 199 | 'CT_KDR': 1.556, 200 | 'CT_KPR': 0.93, 201 | 'CT_MDC': 0.187, 202 | 'CT_MEAN': 4463.0, 203 | 'Deaths': 12, 204 | 'End': 1531116880, 205 | 'HSR': 0.429, 206 | 'KAS': 70.0, 207 | 'KDA': 2.083, 208 | 'KDR': 1.75, 209 | 'KPR': 0.91, 210 | 'Kills': 21, 211 | 'MDC': 0.178, 212 | 'MEAN': 4557.0, 213 | 'Map': 'de_cache', 214 | 'Match_ID': 11, 215 | 'Rating1': 1.46, 216 | 'Round Count': 23, 217 | 'Score': 52, 218 | 'Start': 1531115280, 219 | 'T_HSR': 0.429, 220 | 'T_KAS': 75.0, 221 | 'T_KDA': 2.667, 222 | 'T_KDR': 2.333, 223 | 'T_KPR': 0.88, 224 | 'T_MDC': 0.169, 225 | 'T_MEAN': 4731.0, 226 | 'User_SteamID': 76561198268849559}, 227 | {'Assists': 2, 228 | 'CT_HSR': 0.222, 229 | 'CT_KAS': 93.0, 230 | 'CT_KDA': 1.9, 231 | 'CT_KDR': 1.8, 232 | 'CT_KPR': 1.2, 233 | 'CT_MDC': -0.137, 234 | 'CT_MEAN': 4727.0, 235 | 'Deaths': 19, 236 | 'End': 1531196760, 237 | 'HSR': 0.3, 238 | 'KAS': 79.0, 239 | 'KDA': 1.684, 240 | 'KDR': 1.579, 241 | 'KPR': 1.03, 242 | 'Kills': 30, 243 | 'MDC': 0.023, 244 | 'MEAN': 4652.0, 245 | 'Map': 'de_overpass', 246 | 'Match_ID': 13, 247 | 'Rating1': 1.44, 248 | 'Round Count': 29, 249 | 'Score': 67, 250 | 'Start': 1531193773, 251 | 'T_HSR': 0.417, 252 | 'T_KAS': 64.0, 253 | 'T_KDA': 1.444, 254 | 'T_KDR': 1.333, 255 | 'T_KPR': 0.86, 256 | 'T_MDC': 0.21, 257 | 'T_MEAN': 4571.0, 258 | 'User_SteamID': 76561198268849559}, 259 | {'Assists': 4, 260 | 'CT_HSR': 0.412, 261 | 'CT_KAS': 87.0, 262 | 'CT_KDA': 2.714, 263 | 'CT_KDR': 2.429, 264 | 'CT_KPR': 1.13, 265 | 'CT_MDC': 0.073, 266 | 'CT_MEAN': 4593.0, 267 | 'Deaths': 18, 268 | 'End': 1531199903, 269 | 'HSR': 0.441, 270 | 'KAS': 79.0, 271 | 'KDA': 2.167, 272 | 'KDR': 1.944, 273 | 'KPR': 1.17, 274 | 'Kills': 35, 275 | 'MDC': 0.095, 276 | 'MEAN': 4286.0, 277 | 'Map': 'de_inferno', 278 | 'Match_ID': 14, 279 | 'Rating1': 1.78, 280 | 'Round Count': 29, 281 | 'Score': 78, 282 | 'Start': 1531197100, 283 | 'T_HSR': 0.471, 284 | 'T_KAS': 71.0, 285 | 'T_KDA': 1.818, 286 | 'T_KDR': 1.636, 287 | 'T_KPR': 1.21, 288 | 'T_MDC': 0.14, 289 | 'T_MEAN': 3957.0, 290 | 'User_SteamID': 76561198268849559}, 291 | {'Assists': 1, 292 | 'CT_HSR': 0.5, 293 | 'CT_KAS': 88.0, 294 | 'CT_KDA': 2.75, 295 | 'CT_KDR': 2.5, 296 | 'CT_KPR': 1.25, 297 | 'CT_MDC': 0.338, 298 | 'CT_MEAN': 5300.0, 299 | 'Deaths': 15, 300 | 'End': 1531283820, 301 | 'HSR': 0.4, 302 | 'KAS': 61.0, 303 | 'KDA': 1.333, 304 | 'KDR': 1.267, 305 | 'KPR': 0.87, 306 | 'Kills': 19, 307 | 'MDC': 0.463, 308 | 'MEAN': 4524.0, 309 | 'Map': 'de_cbble', 310 | 'Match_ID': 15, 311 | 'Rating1': 1.31, 312 | 'Round Count': 23, 313 | 'Score': 49, 314 | 'Start': 1531281726, 315 | 'T_HSR': 0.3, 316 | 'T_KAS': 47.0, 317 | 'T_KDA': 0.818, 318 | 'T_KDR': 0.818, 319 | 'T_KPR': 0.67, 320 | 'T_MDC': 0.495, 321 | 'T_MEAN': 4110.0, 322 | 'User_SteamID': 76561198268849559}, 323 | {'Assists': 5, 324 | 'CT_HSR': 0.4, 325 | 'CT_KAS': 80.0, 326 | 'CT_KDA': 2.571, 327 | 'CT_KDR': 2.143, 328 | 'CT_KPR': 1.0, 329 | 'CT_MDC': -0.441, 330 | 'CT_MEAN': 4987.0, 331 | 'Deaths': 10, 332 | 'End': 1531286439, 333 | 'HSR': 0.407, 334 | 'KAS': 83.0, 335 | 'KDA': 3.2, 336 | 'KDR': 2.7, 337 | 'KPR': 1.12, 338 | 'Kills': 27, 339 | 'MDC': -0.059, 340 | 'MEAN': 4965.0, 341 | 'Map': 'de_cache', 342 | 'Match_ID': 16, 343 | 'Rating1': 1.97, 344 | 'Round Count': 24, 345 | 'Score': 67, 346 | 'Start': 1531284268, 347 | 'T_HSR': 0.417, 348 | 'T_KAS': 89.0, 349 | 'T_KDA': 4.667, 350 | 'T_KDR': 4.0, 351 | 'T_KPR': 1.33, 352 | 'T_MDC': 0.436, 353 | 'T_MEAN': 4928.0, 354 | 'User_SteamID': 76561198268849559}, 355 | {'Assists': 0, 356 | 'CT_HSR': 0.5, 357 | 'CT_KAS': 80.0, 358 | 'CT_KDA': 2.444, 359 | 'CT_KDR': 2.444, 360 | 'CT_KPR': 1.47, 361 | 'CT_MDC': 0.131, 362 | 'CT_MEAN': 4787.0, 363 | 'Deaths': 11, 364 | 'End': 1531801913, 365 | 'HSR': 0.469, 366 | 'KAS': 79.0, 367 | 'KDA': 2.909, 368 | 'KDR': 2.909, 369 | 'KPR': 1.33, 370 | 'Kills': 32, 371 | 'MDC': 0.083, 372 | 'MEAN': 4710.0, 373 | 'Map': 'de_overpass', 374 | 'Match_ID': 21, 375 | 'Rating1': 2.15, 376 | 'Round Count': 24, 377 | 'Score': 69, 378 | 'Start': 1531799834, 379 | 'T_HSR': 0.4, 380 | 'T_KAS': 78.0, 381 | 'T_KDA': 5.0, 382 | 'T_KDR': 5.0, 383 | 'T_KPR': 1.11, 384 | 'T_MDC': -0.065, 385 | 'T_MEAN': 4583.0, 386 | 'User_SteamID': 76561198268849559}] 387 | [{'Assists': 6, 388 | 'CT_HSR': 0.5, 389 | 'CT_KAS': 67.0, 390 | 'CT_KDA': 1.045, 391 | 'CT_KDR': 0.773, 392 | 'CT_KPR': 0.67, 393 | 'CT_MDC': 0.197, 394 | 'CT_MEAN': 4337.0, 395 | 'Deaths': 22, 396 | 'End': 1530751490, 397 | 'HSR': 0.471, 398 | 'KAS': 63.0, 399 | 'KDA': 1.045, 400 | 'KDR': 0.773, 401 | 'KPR': 0.57, 402 | 'Kills': 17, 403 | 'MDC': 0.093, 404 | 'MEAN': 4092.0, 405 | 'Map': 'de_train', 406 | 'Match_ID': 1, 407 | 'Rating1': 0.8, 408 | 'Round Count': 30, 409 | 'Score': 43, 410 | 'Start': 1530749022, 411 | 'T_HSR': 0.429, 412 | 'T_KAS': 60.0, 413 | 'T_KDA': 1.0, 414 | 'T_KDR': 0.583, 415 | 'T_KPR': 0.47, 416 | 'T_MDC': -0.122, 417 | 'T_MEAN': 3847.0, 418 | 'User_SteamID': 76561198158189084}, 419 | {'Assists': 7, 420 | 'CT_HSR': 0.286, 421 | 'CT_KAS': 60.0, 422 | 'CT_KDA': 0.846, 423 | 'CT_KDR': 0.538, 424 | 'CT_KPR': 0.47, 425 | 'CT_MDC': -0.241, 426 | 'CT_MEAN': 2927.0, 427 | 'Deaths': 19, 428 | 'End': 1530827310, 429 | 'HSR': 0.211, 430 | 'KAS': 75.0, 431 | 'KDA': 1.368, 432 | 'KDR': 1.0, 433 | 'KPR': 0.68, 434 | 'Kills': 19, 435 | 'MDC': 0.151, 436 | 'MEAN': 4220.0, 437 | 'Map': 'de_cache', 438 | 'Match_ID': 2, 439 | 'Rating1': 0.92, 440 | 'Round Count': 28, 441 | 'Score': 53, 442 | 'Start': 1530824960, 443 | 'T_HSR': 0.167, 444 | 'T_KAS': 92.0, 445 | 'T_KDA': 1.368, 446 | 'T_KDR': 1.0, 447 | 'T_KPR': 0.92, 448 | 'T_MDC': 0.094, 449 | 'T_MEAN': 5712.0, 450 | 'User_SteamID': 76561198158189084}, 451 | {'Assists': 4, 452 | 'CT_HSR': 0.286, 453 | 'CT_KAS': 71.0, 454 | 'CT_KDA': 1.769, 455 | 'CT_KDR': 1.462, 456 | 'CT_KPR': 1.0, 457 | 'CT_MDC': 0.385, 458 | 'CT_MEAN': 3329.0, 459 | 'Deaths': 13, 460 | 'End': 1530860473, 461 | 'HSR': 0.368, 462 | 'KAS': 68.0, 463 | 'KDA': 1.769, 464 | 'KDR': 1.462, 465 | 'KPR': 0.86, 466 | 'Kills': 19, 467 | 'MDC': 0.31, 468 | 'MEAN': 3934.0, 469 | 'Map': 'de_overpass', 470 | 'Match_ID': 3, 471 | 'Rating1': 1.26, 472 | 'Round Count': 22, 473 | 'Score': 45, 474 | 'Start': 1530858399, 475 | 'T_HSR': 0.417, 476 | 'T_KAS': 67.0, 477 | 'T_KDA': 1.857, 478 | 'T_KDR': 1.714, 479 | 'T_KPR': 0.8, 480 | 'T_MDC': 0.333, 481 | 'T_MEAN': 4217.0, 482 | 'User_SteamID': 76561198158189084}, 483 | {'Assists': 2, 484 | 'CT_HSR': 0.143, 485 | 'CT_KAS': 54.0, 486 | 'CT_KDA': 1.211, 487 | 'CT_KDR': 1.105, 488 | 'CT_KPR': 0.54, 489 | 'CT_MDC': 0.283, 490 | 'CT_MEAN': 3919.0, 491 | 'Deaths': 19, 492 | 'End': 1530940311, 493 | 'HSR': 0.1, 494 | 'KAS': 54.0, 495 | 'KDA': 1.211, 496 | 'KDR': 1.105, 497 | 'KPR': 0.71, 498 | 'Kills': 21, 499 | 'MDC': 0.202, 500 | 'MEAN': 4177.0, 501 | 'Map': 'de_overpass', 502 | 'Match_ID': 7, 503 | 'Rating1': 1.04, 504 | 'Round Count': 28, 505 | 'Score': 52, 506 | 'Start': 1530937745, 507 | 'T_HSR': 0.077, 508 | 'T_KAS': 60.0, 509 | 'T_KDA': 1.75, 510 | 'T_KDR': 1.625, 511 | 'T_KPR': 0.87, 512 | 'T_MDC': 0.078, 513 | 'T_MEAN': 4400.0, 514 | 'User_SteamID': 76561198158189084}, 515 | {'Assists': 4, 516 | 'CT_HSR': 0.286, 517 | 'CT_KAS': 73.0, 518 | 'CT_KDA': 1.25, 519 | 'CT_KDR': 1.167, 520 | 'CT_KPR': 0.93, 521 | 'CT_MDC': 0.534, 522 | 'CT_MEAN': 3753.0, 523 | 'Deaths': 20, 524 | 'End': 1531185115, 525 | 'HSR': 0.323, 526 | 'KAS': 80.0, 527 | 'KDA': 1.75, 528 | 'KDR': 1.55, 529 | 'KPR': 1.03, 530 | 'Kills': 31, 531 | 'MDC': 0.376, 532 | 'MEAN': 4312.0, 533 | 'Map': 'de_overpass', 534 | 'Match_ID': 12, 535 | 'Rating1': 1.42, 536 | 'Round Count': 30, 537 | 'Score': 80, 538 | 'Start': 1531182198, 539 | 'T_HSR': 0.353, 540 | 'T_KAS': 87.0, 541 | 'T_KDA': 2.5, 542 | 'T_KDR': 2.125, 543 | 'T_KPR': 1.13, 544 | 'T_MDC': 0.146, 545 | 'T_MEAN': 4870.0, 546 | 'User_SteamID': 76561198158189084}, 547 | {'Assists': 4, 548 | 'CT_HSR': 0.8, 549 | 'CT_KAS': 54.0, 550 | 'CT_KDA': 1.3, 551 | 'CT_KDR': 1.0, 552 | 'CT_KPR': 0.77, 553 | 'CT_MDC': 0.007, 554 | 'CT_MEAN': 4173.0, 555 | 'Deaths': 17, 556 | 'End': 1531375031, 557 | 'HSR': 0.591, 558 | 'KAS': 66.0, 559 | 'KDA': 1.529, 560 | 'KDR': 1.294, 561 | 'KPR': 0.76, 562 | 'Kills': 22, 563 | 'MDC': 0.033, 564 | 'MEAN': 4302.0, 565 | 'Map': 'de_overpass', 566 | 'Match_ID': 17, 567 | 'Rating1': 1.15, 568 | 'Round Count': 29, 569 | 'Score': 64, 570 | 'Start': 1531372179, 571 | 'T_HSR': 0.417, 572 | 'T_KAS': 75.0, 573 | 'T_KDA': 1.857, 574 | 'T_KDR': 1.714, 575 | 'T_KPR': 0.75, 576 | 'T_MDC': 0.067, 577 | 'T_MEAN': 4406.0, 578 | 'User_SteamID': 76561198158189084}, 579 | {'Assists': 4, 580 | 'CT_HSR': 0.4, 581 | 'CT_KAS': 71.0, 582 | 'CT_KDA': 1.889, 583 | 'CT_KDR': 1.667, 584 | 'CT_KPR': 1.07, 585 | 'CT_MDC': 0.327, 586 | 'CT_MEAN': 4525.0, 587 | 'Deaths': 21, 588 | 'End': 1531463686, 589 | 'HSR': 0.52, 590 | 'KAS': 69.0, 591 | 'KDA': 1.333, 592 | 'KDR': 1.143, 593 | 'KPR': 0.86, 594 | 'Kills': 24, 595 | 'MDC': 0.293, 596 | 'MEAN': 3857.0, 597 | 'Map': 'de_cache', 598 | 'Match_ID': 18, 599 | 'Rating1': 1.25, 600 | 'Round Count': 29, 601 | 'Score': 67, 602 | 'Start': 1531461051, 603 | 'T_HSR': 0.7, 604 | 'T_KAS': 67.0, 605 | 'T_KDA': 0.917, 606 | 'T_KDR': 0.75, 607 | 'T_KPR': 0.67, 608 | 'T_MDC': 0.098, 609 | 'T_MEAN': 3233.0, 610 | 'User_SteamID': 76561198158189084}, 611 | {'Assists': 1, 612 | 'CT_HSR': 0.462, 613 | 'CT_KAS': 40.0, 614 | 'CT_KDA': 1.273, 615 | 'CT_KDR': 1.182, 616 | 'CT_KPR': 0.87, 617 | 'CT_MDC': 0.259, 618 | 'CT_MEAN': 2953.0, 619 | 'Deaths': 18, 620 | 'End': 1531615445, 621 | 'HSR': 0.417, 622 | 'KAS': 50.0, 623 | 'KDA': 1.389, 624 | 'KDR': 1.333, 625 | 'KPR': 1.0, 626 | 'Kills': 24, 627 | 'MDC': 0.179, 628 | 'MEAN': 3312.0, 629 | 'Map': 'de_cache', 630 | 'Match_ID': 19, 631 | 'Rating1': 1.57, 632 | 'Round Count': 24, 633 | 'Score': 57, 634 | 'Start': 1531613124, 635 | 'T_HSR': 0.364, 636 | 'T_KAS': 67.0, 637 | 'T_KDA': 1.571, 638 | 'T_KDR': 1.571, 639 | 'T_KPR': 1.22, 640 | 'T_MDC': -0.077, 641 | 'T_MEAN': 3911.0, 642 | 'User_SteamID': 76561198158189084}, 643 | {'Assists': 3, 644 | 'CT_HSR': 0.364, 645 | 'CT_KAS': 64.0, 646 | 'CT_KDA': 1.182, 647 | 'CT_KDR': 1.0, 648 | 'CT_KPR': 0.79, 649 | 'CT_MDC': -0.034, 650 | 'CT_MEAN': 3689.0, 651 | 'Deaths': 17, 652 | 'End': 1531623727, 653 | 'HSR': 0.444, 654 | 'KAS': 64.0, 655 | 'KDA': 1.235, 656 | 'KDR': 1.059, 657 | 'KPR': 0.72, 658 | 'Kills': 18, 659 | 'MDC': 0.096, 660 | 'MEAN': 3782.0, 661 | 'Map': 'de_mirage', 662 | 'Match_ID': 20, 663 | 'Rating1': 1.16, 664 | 'Round Count': 25, 665 | 'Score': 44, 666 | 'Start': 1531621458, 667 | 'T_HSR': 0.571, 668 | 'T_KAS': 64.0, 669 | 'T_KDA': 1.333, 670 | 'T_KDR': 1.167, 671 | 'T_KPR': 0.64, 672 | 'T_MDC': 0.309, 673 | 'T_MEAN': 3900.0, 674 | 'User_SteamID': 76561198158189084}] 675 | 'User Has No Saved Matches' 676 | -------------------------------------------------------------------------------- /cspy_client_app/logs/rounds_json.txt: -------------------------------------------------------------------------------- 1 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534297573}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 0, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 450, "round_kills": 1, "round_killhs": 1, "equip_value": 850}, "match_stats": {"kills": 1, "assists": 0, "deaths": 1, "mvps": 0, "score": 2}}, "previously": {"player": {"state": {"health": 100, "armor": 100}, "match_stats": {"deaths": 0}}}} 2 | 3 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534297649}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 1, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 150, "round_kills": 0, "round_killhs": 0, "equip_value": 1900}, "match_stats": {"kills": 1, "assists": 0, "deaths": 2, "mvps": 0, "score": 2}}, "previously": {"player": {"state": {"health": 81}, "match_stats": {"deaths": 1}}}} 4 | 5 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534297811}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 2, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2050, "round_kills": 0, "round_killhs": 0, "equip_value": 200}, "match_stats": {"kills": 1, "assists": 0, "deaths": 3, "mvps": 0, "score": 2}}, "previously": {"player": {"state": {"health": 100}, "match_stats": {"deaths": 2}}}} 6 | 7 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534297930}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 3, "team_ct": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 150, "round_kills": 0, "round_killhs": 0, "equip_value": 5600}, "match_stats": {"kills": 1, "assists": 0, "deaths": 4, "mvps": 0, "score": 2}}, "previously": {"player": {"state": {"health": 100, "armor": 100}, "match_stats": {"deaths": 3}}}} 8 | 9 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298100}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 4, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1300, "round_kills": 1, "round_killhs": 1, "equip_value": 5100}, "match_stats": {"kills": 2, "assists": 0, "deaths": 5, "mvps": 0, "score": 4}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 4}}}} 10 | 11 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298157}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 5, "team_ct": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 100, "round_kills": 0, "round_killhs": 0, "equip_value": 4650}, "match_stats": {"kills": 2, "assists": 0, "deaths": 6, "mvps": 0, "score": 4}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "defusekit": true}, "match_stats": {"deaths": 5}}}} 12 | 13 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298264}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 6, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1200, "round_kills": 1, "round_killhs": 0, "equip_value": 6000}, "match_stats": {"kills": 3, "assists": 0, "deaths": 7, "mvps": 0, "score": 6}}, "previously": {"player": {"state": {"health": 11, "armor": 87, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 6}}}} 14 | 15 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298345}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 7, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 0, "round_kills": 0, "round_killhs": 0, "equip_value": 4650}, "match_stats": {"kills": 3, "assists": 1, "deaths": 8, "mvps": 0, "score": 7}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "defusekit": true}, "match_stats": {"deaths": 7}}}} 16 | 17 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298451}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 8, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1400, "round_kills": 0, "round_killhs": 0, "equip_value": 300}, "match_stats": {"kills": 3, "assists": 1, "deaths": 9, "mvps": 0, "score": 7}}, "added": {"round": {"bomb": true}}, "previously": {"player": {"state": {"health": 32}, "match_stats": {"deaths": 8}}}} 18 | 19 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298502}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 9, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3300, "round_kills": 1, "round_killhs": 0, "equip_value": 500}, "match_stats": {"kills": 4, "assists": 1, "deaths": 10, "mvps": 0, "score": 9}}, "previously": {"player": {"state": {"health": 21}, "match_stats": {"deaths": 9}}}} 20 | 21 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298626}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 10, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 95, "smoked": 0, "burning": 0, "money": 650, "round_kills": 0, "round_killhs": 0, "equip_value": 5250}, "match_stats": {"kills": 4, "assists": 1, "deaths": 11, "mvps": 0, "score": 9}}, "previously": {"player": {"state": {"health": 22, "armor": 88, "defusekit": true, "flashed": 0}, "match_stats": {"deaths": 10}}}} 22 | 23 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298711}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 11, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2100, "round_kills": 0, "round_killhs": 0, "equip_value": 1450}, "match_stats": {"kills": 4, "assists": 1, "deaths": 12, "mvps": 0, "score": 9}}, "previously": {"player": {"state": {"health": 74, "armor": 96}, "match_stats": {"deaths": 11}}}} 24 | 25 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298814}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 12, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 350, "round_kills": 0, "round_killhs": 0, "equip_value": 5350}, "match_stats": {"kills": 4, "assists": 1, "deaths": 13, "mvps": 0, "score": 9}}, "previously": {"player": {"state": {"health": 46, "armor": 92, "defusekit": true}, "match_stats": {"deaths": 12}}}} 26 | 27 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534298859}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 13, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2050, "round_kills": 0, "round_killhs": 0, "equip_value": 1900}, "match_stats": {"kills": 4, "assists": 1, "deaths": 14, "mvps": 0, "score": 9}}, "previously": {"player": {"state": {"health": 16}, "match_stats": {"deaths": 13}}}} 28 | 29 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299012}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 14, "team_ct": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 350, "round_kills": 1, "round_killhs": 0, "equip_value": 5450}, "match_stats": {"kills": 5, "assists": 1, "deaths": 15, "mvps": 0, "score": 11}}, "previously": {"player": {"state": {"health": 55, "armor": 96, "defusekit": true}, "match_stats": {"deaths": 14}}}} 30 | 31 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299156}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 16, "team_ct": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 85, "armor": 92, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3700, "round_kills": 1, "round_killhs": 1, "equip_value": 850}, "match_stats": {"kills": 6, "assists": 1, "deaths": 15, "mvps": 0, "score": 13}}, "previously": {"map": {"round": 15}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 450}}}, "added": {"round": {"win_team": true}}} 32 | 33 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299194}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 16, "team_ct": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 0, "round_kills": 0, "round_killhs": 0, "equip_value": 3950}, "match_stats": {"kills": 6, "assists": 1, "deaths": 16, "mvps": 0, "score": 13}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "helmet": true, "flashed": 14}, "match_stats": {"deaths": 15}}}} 34 | 35 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299298}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 17, "team_ct": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 900, "round_kills": 0, "round_killhs": 0, "equip_value": 500}, "match_stats": {"kills": 6, "assists": 1, "deaths": 17, "mvps": 0, "score": 13}}, "previously": {"player": {"state": {"health": 51}, "match_stats": {"deaths": 16}}}} 36 | 37 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299376}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 18, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2800, "round_kills": 0, "round_killhs": 0, "equip_value": 200}, "match_stats": {"kills": 6, "assists": 1, "deaths": 18, "mvps": 0, "score": 13}}, "previously": {"player": {"state": {"health": 29}, "match_stats": {"deaths": 17}}}} 38 | 39 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299427}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 19, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1200, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 6, "assists": 1, "deaths": 19, "mvps": 0, "score": 13}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "helmet": true}, "match_stats": {"deaths": 18}}}} 40 | 41 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299581}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 21, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 3300, "round_kills": 0, "round_killhs": 0, "equip_value": 4600}, "match_stats": {"kills": 6, "assists": 2, "deaths": 19, "mvps": 0, "score": 14}}, "previously": {"map": {"round": 20}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 50}}}, "added": {"round": {"win_team": true}}} 42 | 43 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299678}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 22, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 94, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4750, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 6, "assists": 2, "deaths": 19, "mvps": 0, "score": 16}}, "previously": {"map": {"round": 21, "team_t": {"score": 10}}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 1500}}}, "added": {"round": {"win_team": true}}} 44 | 45 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299729}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 22, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3850, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 6, "assists": 2, "deaths": 20, "mvps": 0, "score": 16}}, "previously": {"player": {"state": {"health": 100, "armor": 97, "helmet": true}, "match_stats": {"deaths": 19}}}} 46 | 47 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299780}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 23, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 12, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2600, "round_kills": 1, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 2, "deaths": 21, "mvps": 0, "score": 18}}, "previously": {"player": {"state": {"health": 97, "armor": 98, "helmet": true}, "match_stats": {"deaths": 20}}}} 48 | 49 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299867}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 24, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 255, "burning": 0, "money": 3750, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 2, "deaths": 22, "mvps": 0, "score": 18}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "helmet": true, "smoked": 91}, "match_stats": {"deaths": 21}}}} 50 | 51 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534299948}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 26, "team_ct": {"score": 12, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 2250, "round_kills": 0, "round_killhs": 0, "equip_value": 4700}, "match_stats": {"kills": 7, "assists": 2, "deaths": 23, "mvps": 0, "score": 18}}, "previously": {"map": {"round": 25}, "round": {"phase": "live"}, "player": {"state": {"health": 100, "armor": 100, "helmet": true, "money": 350}, "match_stats": {"deaths": 22}}}, "added": {"round": {"win_team": true}}} 52 | 53 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534300032}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 26, "team_ct": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 650, "round_kills": 1, "round_killhs": 0, "equip_value": 4500}, "match_stats": {"kills": 8, "assists": 2, "deaths": 24, "mvps": 0, "score": 20}}, "previously": {"player": {"state": {"health": 2, "armor": 82, "helmet": true}, "match_stats": {"deaths": 23}}}} 54 | 55 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534300106}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 27, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 500, "round_kills": 0, "round_killhs": 0, "equip_value": 2750}, "match_stats": {"kills": 8, "assists": 2, "deaths": 25, "mvps": 0, "score": 20}}, "previously": {"player": {"state": {"health": 48, "armor": 95, "helmet": true}, "match_stats": {"deaths": 24}}}} 56 | 57 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198158189084", "timestamp": 1534300158}, "map": {"mode": "competitive", "name": "de_train", "phase": "live", "round": 28, "team_ct": {"score": 15, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198158189084", "name": "gumby", "observer_slot": 5, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 100, "round_kills": 0, "round_killhs": 0, "equip_value": 3500}, "match_stats": {"kills": 8, "assists": 2, "deaths": 26, "mvps": 0, "score": 20}}, "previously": {"player": {"state": {"health": 78, "armor": 90, "helmet": true}, "match_stats": {"deaths": 25}}}} 58 | 59 | ---- 60 | 61 | "The Incorrect Match Before Duplicate Method Fix (27 Rounds)" 62 | 63 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359227}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 1, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 81, "armor": 97, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3700, "round_kills": 1, "round_killhs": 1, "equip_value": 850}, "match_stats": {"kills": 1, "assists": 0, "deaths": 0, "mvps": 0, "score": 2}}, "previously": {"map": {"round": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 450}}}, "added": {"round": {"win_team": true}}} 64 | 65 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359310}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 2, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4450, "round_kills": 3, "round_killhs": 2, "equip_value": 3900}, "match_stats": {"kills": 4, "assists": 1, "deaths": 0, "mvps": 1, "score": 11}}, "previously": {"map": {"round": 1}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 900, "round_kills": 2, "round_killhs": 1}, "match_stats": {"kills": 3, "mvps": 0, "score": 9}}}, "added": {"round": {"win_team": true}}} 66 | 67 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359412}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 3, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T", "bomb": "exploded"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 6850, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 4, "assists": 1, "deaths": 0, "mvps": 1, "score": 12}}, "previously": {"map": {"round": 2, "team_t": {"score": 2}}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 3350}, "match_stats": {"score": 11}}}, "added": {"round": {"win_team": true}}} 68 | 69 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359537}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 4, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 28, "armor": 88, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 10300, "round_kills": 3, "round_killhs": 2, "equip_value": 4100}, "match_stats": {"kills": 7, "assists": 1, "deaths": 0, "mvps": 2, "score": 18}}, "previously": {"map": {"round": 3}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 7050}, "match_stats": {"mvps": 1}}}, "added": {"round": {"win_team": true}}} 70 | 71 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359572}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 4, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6500, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 1, "deaths": 1, "mvps": 2, "score": 18}}, "previously": {"player": {"state": {"health": 100, "armor": 88, "helmet": true}, "match_stats": {"deaths": 0}}}} 72 | 73 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359709}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 5, "team_ct": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 400, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 1, "deaths": 2, "mvps": 2, "score": 18}}, "previously": {"player": {"state": {"health": 18, "armor": 75, "helmet": true}, "match_stats": {"deaths": 1}}}} 74 | 75 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359854}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 6, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 900, "round_kills": 1, "round_killhs": 1, "equip_value": 1700}, "match_stats": {"kills": 8, "assists": 2, "deaths": 3, "mvps": 2, "score": 21}}, "previously": {"player": {"state": {"health": 46, "armor": 80, "helmet": true}, "match_stats": {"deaths": 2}}}} 76 | 77 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359955}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 10, "armor": 92, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 6000, "round_kills": 2, "round_killhs": 1, "equip_value": 7050}, "match_stats": {"kills": 10, "assists": 2, "deaths": 3, "mvps": 3, "score": 27}}, "previously": {"map": {"round": 7}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2750}, "match_stats": {"mvps": 2}}}, "added": {"round": {"win_team": true}}} 78 | 79 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360039}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 5700, "round_kills": 1, "round_killhs": 0, "equip_value": 7150}, "match_stats": {"kills": 11, "assists": 2, "deaths": 4, "mvps": 3, "score": 29}}, "previously": {"player": {"state": {"health": 7, "armor": 71, "helmet": true}, "match_stats": {"deaths": 3}}}} 80 | 81 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360153}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 9, "team_ct": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3200, "round_kills": 2, "round_killhs": 1, "equip_value": 5000}, "match_stats": {"kills": 13, "assists": 2, "deaths": 5, "mvps": 3, "score": 36}}, "previously": {"player": {"state": {"health": 47, "armor": 87, "helmet": true}, "match_stats": {"deaths": 4}}}} 82 | 83 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360212}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 10, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 700, "round_kills": 1, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 14, "assists": 3, "deaths": 6, "mvps": 3, "score": 39}}, "previously": {"player": {"state": {"health": 9, "armor": 65, "helmet": true}, "match_stats": {"assists": 2, "deaths": 5, "score": 38}}}} 84 | 85 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360361}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 11, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 350, "round_kills": 1, "round_killhs": 1, "equip_value": 4100}, "match_stats": {"kills": 15, "assists": 3, "deaths": 7, "mvps": 3, "score": 41}}, "previously": {"player": {"state": {"health": 47, "armor": 98, "helmet": true}, "match_stats": {"deaths": 6}}}} 86 | 87 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360445}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 13, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 11, "armor": 71, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 5650, "round_kills": 3, "round_killhs": 1, "equip_value": 5000}, "match_stats": {"kills": 18, "assists": 3, "deaths": 7, "mvps": 4, "score": 47}}, "previously": {"map": {"round": 12}, "round": {"phase": "live"}, "player": {"state": {"money": 2400}, "match_stats": {"mvps": 3}}}, "added": {"round": {"win_team": true}}} 88 | 89 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360489}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 13, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 5250, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 18, "assists": 3, "deaths": 8, "mvps": 4, "score": 47}}, "previously": {"player": {"state": {"health": 100, "armor": 71, "helmet": true}, "match_stats": {"deaths": 7}}}} 90 | 91 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360675}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "intermission", "round": 15, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 54, "armor": 94, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 5500, "round_kills": 3, "round_killhs": 0, "equip_value": 5300}, "match_stats": {"kills": 21, "assists": 3, "deaths": 8, "mvps": 5, "score": 55}}, "previously": {"map": {"phase": "live", "round": 14}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2250}, "match_stats": {"kills": 20, "mvps": 4, "score": 52}}}, "added": {"round": {"win_team": true}}} 92 | 93 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360756}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 15, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 150, "round_kills": 0, "round_killhs": 0, "equip_value": 850}, "match_stats": {"kills": 21, "assists": 3, "deaths": 9, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 22, "armor": 52}, "match_stats": {"deaths": 8}}}} 94 | 95 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360833}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 16, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 0, "round_kills": 0, "round_killhs": 0, "equip_value": 1550}, "match_stats": {"kills": 21, "assists": 3, "deaths": 10, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 6, "armor": 94}, "match_stats": {"deaths": 9}}}} 96 | 97 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360906}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 17, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1900, "round_kills": 0, "round_killhs": 0, "equip_value": 200}, "match_stats": {"kills": 21, "assists": 3, "deaths": 11, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 3}, "match_stats": {"deaths": 10}}}} 98 | 99 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360953}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 18, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4300, "round_kills": 0, "round_killhs": 0, "equip_value": 200}, "match_stats": {"kills": 21, "assists": 4, "deaths": 11, "mvps": 5, "score": 56}}, "previously": {"map": {"round": 17}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198282514833", "clan": "$.B.$", "name": "SourRumy", "observer_slot": 0, "state": {"health": 71, "money": 1900}, "match_stats": {"kills": 6, "assists": 0, "deaths": 12, "mvps": 2, "score": 18}}}, "added": {"round": {"win_team": true}}} 100 | 101 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361008}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 18, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 300, "round_kills": 1, "round_killhs": 1, "equip_value": 4500}, "match_stats": {"kills": 22, "assists": 4, "deaths": 12, "mvps": 5, "score": 58}}, "previously": {"player": {"state": {"health": 67, "armor": 95, "helmet": true}, "match_stats": {"deaths": 11}}}} 102 | 103 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361163}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 19, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1400, "round_kills": 1, "round_killhs": 0, "equip_value": 6000}, "match_stats": {"kills": 23, "assists": 5, "deaths": 13, "mvps": 5, "score": 61}}, "previously": {"player": {"state": {"health": 67, "armor": 95, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 12}}}} 104 | 105 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361261}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 20, "team_ct": {"score": 12, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 450, "round_kills": 1, "round_killhs": 1, "equip_value": 4900}, "match_stats": {"kills": 24, "assists": 5, "deaths": 14, "mvps": 5, "score": 63}}, "previously": {"player": {"state": {"health": 34, "armor": 88, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 13}}}} 106 | 107 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361477}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 22, "team_ct": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT", "bomb": "defused"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4100, "round_kills": 2, "round_killhs": 1, "equip_value": 4350}, "match_stats": {"kills": 26, "assists": 6, "deaths": 14, "mvps": 5, "score": 69}}, "previously": {"map": {"round": 21}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 600}, "match_stats": {"score": 68}}}, "added": {"round": {"win_team": true}}} 108 | 109 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361523}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 22, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3150, "round_kills": 1, "round_killhs": 1, "equip_value": 5600}, "match_stats": {"kills": 27, "assists": 6, "deaths": 15, "mvps": 5, "score": 71}}, "previously": {"player": {"state": {"health": 3, "armor": 92, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 14}}}} 110 | 111 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361667}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 24, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T", "bomb": "exploded"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4750, "round_kills": 0, "round_killhs": 0, "equip_value": 1900}, "match_stats": {"kills": 27, "assists": 6, "deaths": 15, "mvps": 5, "score": 71}}, "previously": {"map": {"round": 23}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2850}}}, "added": {"round": {"win_team": true}}} 112 | 113 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361728}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 24, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 255, "burning": 0, "money": 100, "round_kills": 0, "round_killhs": 0, "equip_value": 3250}, "match_stats": {"kills": 27, "assists": 6, "deaths": 16, "mvps": 5, "score": 71}}, "previously": {"player": {"state": {"health": 73, "armor": 96, "defusekit": true}, "match_stats": {"deaths": 15}}}} 114 | 115 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361906}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "gameover", "round": 26, "team_ct": {"score": 15, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT", "bomb": "defused"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4550, "round_kills": 2, "round_killhs": 0, "equip_value": 3550}, "match_stats": {"kills": 29, "assists": 8, "deaths": 16, "mvps": 6, "score": 79}}, "previously": {"map": {"phase": "live", "round": 25}, "round": {"phase": "live", "bomb": "planted"}, "player": {"observer_slot": 5, "state": {"money": 750}, "match_stats": {"mvps": 5, "score": 77}}}, "added": {"round": {"win_team": true}}} 116 | 117 | ---- 118 | 119 | "The Correct Match After Duplicate Method Fix (26 Rounds)" 120 | 121 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359227}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 1, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 81, "armor": 97, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3700, "round_kills": 1, "round_killhs": 1, "equip_value": 850}, "match_stats": {"kills": 1, "assists": 0, "deaths": 0, "mvps": 0, "score": 2}}, "previously": {"map": {"round": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 450}}}, "added": {"round": {"win_team": true}}} 122 | 123 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359310}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 2, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4450, "round_kills": 3, "round_killhs": 2, "equip_value": 3900}, "match_stats": {"kills": 4, "assists": 1, "deaths": 0, "mvps": 1, "score": 11}}, "previously": {"map": {"round": 1}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 900, "round_kills": 2, "round_killhs": 1}, "match_stats": {"kills": 3, "mvps": 0, "score": 9}}}, "added": {"round": {"win_team": true}}} 124 | 125 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359412}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 3, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T", "bomb": "exploded"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 6850, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 4, "assists": 1, "deaths": 0, "mvps": 1, "score": 12}}, "previously": {"map": {"round": 2, "team_t": {"score": 2}}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 3350}, "match_stats": {"score": 11}}}, "added": {"round": {"win_team": true}}} 126 | 127 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359537}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 4, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 28, "armor": 88, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 10300, "round_kills": 3, "round_killhs": 2, "equip_value": 4100}, "match_stats": {"kills": 7, "assists": 1, "deaths": 0, "mvps": 2, "score": 18}}, "previously": {"map": {"round": 3}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 7050}, "match_stats": {"mvps": 1}}}, "added": {"round": {"win_team": true}}} 128 | 129 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359572}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 4, "team_ct": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6500, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 1, "deaths": 1, "mvps": 2, "score": 18}}, "previously": {"player": {"state": {"health": 100, "armor": 88, "helmet": true}, "match_stats": {"deaths": 0}}}} 130 | 131 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359709}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 5, "team_ct": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 400, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 7, "assists": 1, "deaths": 2, "mvps": 2, "score": 18}}, "previously": {"player": {"state": {"health": 18, "armor": 75, "helmet": true}, "match_stats": {"deaths": 1}}}} 132 | 133 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359854}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 6, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 900, "round_kills": 1, "round_killhs": 1, "equip_value": 1700}, "match_stats": {"kills": 8, "assists": 2, "deaths": 3, "mvps": 2, "score": 21}}, "previously": {"player": {"state": {"health": 46, "armor": 80, "helmet": true}, "match_stats": {"deaths": 2}}}} 134 | 135 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534359955}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 10, "armor": 92, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 6000, "round_kills": 2, "round_killhs": 1, "equip_value": 7050}, "match_stats": {"kills": 10, "assists": 2, "deaths": 3, "mvps": 3, "score": 27}}, "previously": {"map": {"round": 7}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2750}, "match_stats": {"mvps": 2}}}, "added": {"round": {"win_team": true}}} 136 | 137 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360039}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 5700, "round_kills": 1, "round_killhs": 0, "equip_value": 7150}, "match_stats": {"kills": 11, "assists": 2, "deaths": 4, "mvps": 3, "score": 29}}, "previously": {"player": {"state": {"health": 7, "armor": 71, "helmet": true}, "match_stats": {"deaths": 3}}}} 138 | 139 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360153}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 9, "team_ct": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3200, "round_kills": 2, "round_killhs": 1, "equip_value": 5000}, "match_stats": {"kills": 13, "assists": 2, "deaths": 5, "mvps": 3, "score": 36}}, "previously": {"player": {"state": {"health": 47, "armor": 87, "helmet": true}, "match_stats": {"deaths": 4}}}} 140 | 141 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360212}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 10, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 700, "round_kills": 1, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 14, "assists": 3, "deaths": 6, "mvps": 3, "score": 39}}, "previously": {"player": {"state": {"health": 9, "armor": 65, "helmet": true}, "match_stats": {"assists": 2, "deaths": 5, "score": 38}}}} 142 | 143 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360361}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 11, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 350, "round_kills": 1, "round_killhs": 1, "equip_value": 4100}, "match_stats": {"kills": 15, "assists": 3, "deaths": 7, "mvps": 3, "score": 41}}, "previously": {"player": {"state": {"health": 47, "armor": 98, "helmet": true}, "match_stats": {"deaths": 6}}}} 144 | 145 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360445}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 13, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 11, "armor": 71, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 5650, "round_kills": 3, "round_killhs": 1, "equip_value": 5000}, "match_stats": {"kills": 18, "assists": 3, "deaths": 7, "mvps": 4, "score": 47}}, "previously": {"map": {"round": 12}, "round": {"phase": "live"}, "player": {"state": {"money": 2400}, "match_stats": {"mvps": 3}}}, "added": {"round": {"win_team": true}}} 146 | 147 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360489}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 13, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 5250, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 18, "assists": 3, "deaths": 8, "mvps": 4, "score": 47}}, "previously": {"player": {"state": {"health": 100, "armor": 71, "helmet": true}, "match_stats": {"deaths": 7}}}} 148 | 149 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360675}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "intermission", "round": 15, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "T", "activity": "playing", "state": {"health": 54, "armor": 94, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 5500, "round_kills": 3, "round_killhs": 0, "equip_value": 5300}, "match_stats": {"kills": 21, "assists": 3, "deaths": 8, "mvps": 5, "score": 55}}, "previously": {"map": {"phase": "live", "round": 14}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2250}, "match_stats": {"kills": 20, "mvps": 4, "score": 52}}}, "added": {"round": {"win_team": true}}} 150 | 151 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360756}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 15, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 150, "round_kills": 0, "round_killhs": 0, "equip_value": 850}, "match_stats": {"kills": 21, "assists": 3, "deaths": 9, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 22, "armor": 52}, "match_stats": {"deaths": 8}}}} 152 | 153 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360833}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 16, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 0, "round_kills": 0, "round_killhs": 0, "equip_value": 1550}, "match_stats": {"kills": 21, "assists": 3, "deaths": 10, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 6, "armor": 94}, "match_stats": {"deaths": 9}}}} 154 | 155 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534360906}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 17, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1900, "round_kills": 0, "round_killhs": 0, "equip_value": 200}, "match_stats": {"kills": 21, "assists": 3, "deaths": 11, "mvps": 5, "score": 55}}, "previously": {"player": {"state": {"health": 3}, "match_stats": {"deaths": 10}}}} 156 | 157 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361008}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 18, "team_ct": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 300, "round_kills": 1, "round_killhs": 1, "equip_value": 4500}, "match_stats": {"kills": 22, "assists": 4, "deaths": 12, "mvps": 5, "score": 58}}, "previously": {"player": {"state": {"health": 67, "armor": 95, "helmet": true}, "match_stats": {"deaths": 11}}}} 158 | 159 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361163}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 19, "team_ct": {"score": 11, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1400, "round_kills": 1, "round_killhs": 0, "equip_value": 6000}, "match_stats": {"kills": 23, "assists": 5, "deaths": 13, "mvps": 5, "score": 61}}, "previously": {"player": {"state": {"health": 67, "armor": 95, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 12}}}} 160 | 161 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361261}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 20, "team_ct": {"score": 12, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 450, "round_kills": 1, "round_killhs": 1, "equip_value": 4900}, "match_stats": {"kills": 24, "assists": 5, "deaths": 14, "mvps": 5, "score": 63}}, "previously": {"player": {"state": {"health": 34, "armor": 88, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 13}}}} 162 | 163 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361477}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 22, "team_ct": {"score": 13, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT", "bomb": "defused"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4100, "round_kills": 2, "round_killhs": 1, "equip_value": 4350}, "match_stats": {"kills": 26, "assists": 6, "deaths": 14, "mvps": 5, "score": 69}}, "previously": {"map": {"round": 21}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 600}, "match_stats": {"score": 68}}}, "added": {"round": {"win_team": true}}} 164 | 165 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361523}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 22, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3150, "round_kills": 1, "round_killhs": 1, "equip_value": 5600}, "match_stats": {"kills": 27, "assists": 6, "deaths": 15, "mvps": 5, "score": 71}}, "previously": {"player": {"state": {"health": 3, "armor": 92, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 14}}}} 166 | 167 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361667}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 24, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T", "bomb": "exploded"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4750, "round_kills": 0, "round_killhs": 0, "equip_value": 1900}, "match_stats": {"kills": 27, "assists": 6, "deaths": 15, "mvps": 5, "score": 71}}, "previously": {"map": {"round": 23}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 2850}}}, "added": {"round": {"win_team": true}}} 168 | 169 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361728}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 24, "team_ct": {"score": 14, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 255, "burning": 0, "money": 100, "round_kills": 0, "round_killhs": 0, "equip_value": 3250}, "match_stats": {"kills": 27, "assists": 6, "deaths": 16, "mvps": 5, "score": 71}}, "previously": {"player": {"state": {"health": 73, "armor": 96, "defusekit": true}, "match_stats": {"deaths": 15}}}} 170 | 171 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13647, "steamid": "76561198268849559", "timestamp": 1534361906}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "gameover", "round": 26, "team_ct": {"score": 15, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 10, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT", "bomb": "defused"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 6, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4550, "round_kills": 2, "round_killhs": 0, "equip_value": 3550}, "match_stats": {"kills": 29, "assists": 8, "deaths": 16, "mvps": 6, "score": 79}}, "previously": {"map": {"phase": "live", "round": 25}, "round": {"phase": "live", "bomb": "planted"}, "player": {"observer_slot": 5, "state": {"money": 750}, "match_stats": {"mvps": 5, "score": 77}}}, "added": {"round": {"win_team": true}}} 172 | 173 | ---- 174 | 175 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441415}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 1, "team_ct": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 62, "armor": 79, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4150, "round_kills": 3, "round_killhs": 2, "equip_value": 850}, "match_stats": {"kills": 2, "assists": 0, "deaths": 0, "mvps": 1, "score": 6}}, "previously": {"map": {"round": 0, "team_ct": {"score": 0}}, "round": {"phase": "live"}, "player": {"state": {"money": 600, "round_kills": 2}, "match_stats": {"kills": 1, "mvps": 0, "score": 4}}}, "added": {"round": {"win_team": true}}} 176 | 177 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441486}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 2, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 3300, "round_kills": 0, "round_killhs": 0, "equip_value": 4300}, "match_stats": {"kills": 2, "assists": 0, "deaths": 0, "mvps": 1, "score": 6}}, "previously": {"map": {"round": 1, "team_ct": {"score": 1}}, "round": {"phase": "live"}, "player": {"state": {"money": 50}}}, "added": {"round": {"win_team": true}}} 178 | 179 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441555}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 3, "team_ct": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 59, "armor": 97, "helmet": true, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 5150, "round_kills": 1, "round_killhs": 0, "equip_value": 6000}, "match_stats": {"kills": 3, "assists": 0, "deaths": 0, "mvps": 1, "score": 8}}, "previously": {"map": {"round": 2}, "round": {"phase": "live"}, "player": {"state": {"money": 1900}}}, "added": {"round": {"win_team": true}}} 180 | 181 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441636}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 4, "team_ct": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 73, "armor": 93, "helmet": true, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 8400, "round_kills": 2, "round_killhs": 2, "equip_value": 6000}, "match_stats": {"kills": 5, "assists": 0, "deaths": 0, "mvps": 2, "score": 12}}, "previously": {"map": {"round": 3}, "round": {"phase": "live"}, "player": {"state": {"money": 5150}, "match_stats": {"mvps": 1}}}, "added": {"round": {"win_team": true}}} 182 | 183 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441690}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 5, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 93, "helmet": true, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 8150, "round_kills": 2, "round_killhs": 0, "equip_value": 5600}, "match_stats": {"kills": 7, "assists": 0, "deaths": 0, "mvps": 3, "score": 16}}, "previously": {"map": {"round": 4}, "round": {"phase": "live"}, "player": {"state": {"money": 4900}, "match_stats": {"mvps": 2}}}, "added": {"round": {"win_team": true}}} 184 | 185 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441790}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 6, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 0, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 8750, "round_kills": 0, "round_killhs": 0, "equip_value": 5700}, "match_stats": {"kills": 7, "assists": 0, "deaths": 1, "mvps": 3, "score": 16}}, "previously": {"map": {"round": 5}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"health": 97, "armor": 93, "helmet": true, "defusekit": true, "money": 7350}, "match_stats": {"deaths": 0}}}, "added": {"round": {"win_team": true}}} 186 | 187 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441829}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 6, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 1, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3250, "round_kills": 0, "round_killhs": 0, "equip_value": 5700}, "match_stats": {"kills": 7, "assists": 0, "deaths": 2, "mvps": 3, "score": 16}}, "previously": {"player": {"state": {"health": 100, "armor": 100, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 1}}}} 188 | 189 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534441997}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 68, "armor": 95, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6350, "round_kills": 1, "round_killhs": 0, "equip_value": 2550}, "match_stats": {"kills": 8, "assists": 1, "deaths": 2, "mvps": 3, "score": 19}}, "previously": {"map": {"round": 7}, "round": {"phase": "live"}, "player": {"state": {"money": 3100}}}, "added": {"round": {"win_team": true}}} 190 | 191 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442065}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 8, "team_ct": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 2, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3450, "round_kills": 0, "round_killhs": 0, "equip_value": 4600}, "match_stats": {"kills": 8, "assists": 1, "deaths": 3, "mvps": 3, "score": 19}}, "previously": {"player": {"state": {"health": 88, "armor": 95, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 2}}}} 192 | 193 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442204}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 10, "team_ct": {"score": 6, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 23, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6700, "round_kills": 1, "round_killhs": 0, "equip_value": 1900}, "match_stats": {"kills": 9, "assists": 3, "deaths": 3, "mvps": 3, "score": 23}}, "previously": {"map": {"round": 9}, "round": {"phase": "live"}, "player": {"state": {"money": 3150, "round_kills": 0}, "match_stats": {"kills": 8, "score": 21}}}, "added": {"round": {"win_team": true}}} 194 | 195 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442305}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 11, "team_ct": {"score": 7, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 58, "armor": 90, "helmet": true, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4050, "round_kills": 1, "round_killhs": 0, "equip_value": 7650}, "match_stats": {"kills": 10, "assists": 3, "deaths": 3, "mvps": 3, "score": 25}}, "previously": {"map": {"round": 10}, "round": {"phase": "live"}, "player": {"state": {"money": 800}}}, "added": {"round": {"win_team": true}}} 196 | 197 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442409}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 11, "team_ct": {"score": 8, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 3250, "round_kills": 3, "round_killhs": 0, "equip_value": 7950}, "match_stats": {"kills": 13, "assists": 3, "deaths": 4, "mvps": 3, "score": 31}}, "previously": {"player": {"state": {"health": 44, "armor": 75, "helmet": true, "defusekit": true}, "match_stats": {"deaths": 3}}}} 198 | 199 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442490}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 13, "team_ct": {"score": 9, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": true, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 4550, "round_kills": 1, "round_killhs": 1, "equip_value": 5700}, "match_stats": {"kills": 14, "assists": 3, "deaths": 4, "mvps": 4, "score": 33}}, "previously": {"map": {"round": 12}, "round": {"phase": "live"}, "player": {"state": {"money": 1300}}}, "added": {"round": {"win_team": true}}} 200 | 201 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442570}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 14, "team_ct": {"score": 10, "timeouts_remaining": 0, "matches_won_this_series": 0}, "team_t": {"score": 3, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6550, "round_kills": 2, "round_killhs": 0, "equip_value": 6200}, "match_stats": {"kills": 16, "assists": 3, "deaths": 5, "mvps": 4, "score": 37}}, "previously": {"map": {"round": 13}, "round": {"phase": "live"}, "player": {"state": {"health": 13, "armor": 91, "helmet": true, "defusekit": true, "money": 5150}, "match_stats": {"deaths": 4}}}, "added": {"round": {"win_team": true}}} 202 | 203 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442743}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "intermission", "round": 15, "team_ct": {"score": 10, "timeouts_remaining": 0, "matches_won_this_series": 0}, "team_t": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "CT"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "CT", "activity": "playing", "state": {"health": 100, "armor": 100, "helmet": false, "defusekit": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 3600, "round_kills": 2, "round_killhs": 0, "equip_value": 6400}, "match_stats": {"kills": 18, "assists": 3, "deaths": 5, "mvps": 5, "score": 41}}, "previously": {"map": {"phase": "live", "round": 14}, "round": {"phase": "live"}, "player": {"state": {"money": 250, "round_kills": 1}, "match_stats": {"kills": 17, "mvps": 4, "score": 39}}}, "added": {"round": {"win_team": true}}} 204 | 205 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442812}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 16, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 12, "timeouts_remaining": 0, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "T", "activity": "playing", "state": {"health": 44, "armor": 70, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 4300, "round_kills": 3, "round_killhs": 3, "equip_value": 850}, "match_stats": {"kills": 21, "assists": 3, "deaths": 5, "mvps": 6, "score": 48}}, "previously": {"map": {"round": 15, "team_t": {"score": 11}}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 750, "round_kills": 2, "round_killhs": 2}, "match_stats": {"kills": 20, "mvps": 5, "score": 46}}}, "added": {"round": {"win_team": true}}} 206 | 207 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442908}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 17, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 0, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "T", "activity": "playing", "state": {"health": 91, "armor": 98, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 3650, "round_kills": 0, "round_killhs": 0, "equip_value": 4600}, "match_stats": {"kills": 21, "assists": 3, "deaths": 5, "mvps": 6, "score": 50}}, "previously": {"map": {"round": 16, "team_t": {"score": 12}}, "round": {"phase": "live", "bomb": "planted"}, "player": {"state": {"money": 400}}}, "added": {"round": {"win_team": true}}} 208 | 209 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534442978}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 18, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 13, "timeouts_remaining": 0, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "over", "win_team": "T"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "T", "activity": "playing", "state": {"health": 74, "armor": 98, "helmet": true, "flashed": 0, "smoked": 0, "burning": 0, "money": 7100, "round_kills": 2, "round_killhs": 1, "equip_value": 5000}, "match_stats": {"kills": 23, "assists": 3, "deaths": 5, "mvps": 7, "score": 54}}, "previously": {"map": {"round": 17}, "round": {"phase": "live"}, "player": {"state": {"health": 100, "money": 3550, "round_kills": 1, "round_killhs": 0}, "match_stats": {"kills": 22, "mvps": 6, "score": 52}}}, "added": {"round": {"win_team": true}}} 210 | 211 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534443032}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 18, "team_ct": {"score": 4, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 14, "timeouts_remaining": 0, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 6700, "round_kills": 0, "round_killhs": 0, "equip_value": 5000}, "match_stats": {"kills": 23, "assists": 3, "deaths": 6, "mvps": 7, "score": 54}}, "previously": {"player": {"state": {"health": 73, "armor": 91, "helmet": true}, "match_stats": {"deaths": 5}}}} 212 | 213 | {"provider": {"name": "Counter-Strike: Global Offensive", "appid": 730, "version": 13648, "steamid": "76561198268849559", "timestamp": 1534443144}, "map": {"mode": "competitive", "name": "de_overpass", "phase": "live", "round": 19, "team_ct": {"score": 5, "timeouts_remaining": 1, "matches_won_this_series": 0}, "team_t": {"score": 14, "timeouts_remaining": 0, "matches_won_this_series": 0}, "num_matches_to_win_series": 0, "current_spectators": 0, "souvenirs_total": 0}, "round": {"phase": "live", "bomb": "planted"}, "player": {"steamid": "76561198268849559", "name": "post office malone", "observer_slot": 1, "team": "T", "activity": "playing", "state": {"health": 0, "armor": 0, "helmet": false, "flashed": 0, "smoked": 0, "burning": 0, "money": 1450, "round_kills": 1, "round_killhs": 0, "equip_value": 6750}, "match_stats": {"kills": 24, "assists": 4, "deaths": 7, "mvps": 7, "score": 57}}, "previously": {"player": {"state": {"health": 46, "armor": 92, "helmet": true}, "match_stats": {"deaths": 6}}}} 214 | 215 | ---- 216 | 217 | --------------------------------------------------------------------------------