From 5345d95cfe03a517ec3875245af08914d6abe512 Mon Sep 17 00:00:00 2001 From: Leonard Jonathan Oh Date: Wed, 22 Nov 2023 02:35:58 +0000 Subject: [PATCH] Change (docker): Combine nginx and php to a single image for both `ASP` and `bf2sclone` with env var support for configuration Previous: In <= v2.5.x, `asp` and `bf2sclone` each had separate `nginx` and `php` images. Now: Single `asp` and `bf2sclone` images containing both `nginx` and `php`, with environment variable support, and entrypoint that sets the correct permissions. Benefits: - Easier to deploy / upgrade. No need to separate `asp-nginx` and `asp-php` containers - Environment variable configuration means no more need to mount `config.php` into `asp` and `bf2sclone` containers - Entrypoint script sets permissions on volumes. `init-container` should only need to set permissions for `db` volume. Notable changes: - Add documentation for upgrading docker images to v2.6.x from prior versions - Update `./docs/examples` - Add tests for production builds for examples in `./docs/examples` Closes #132 --- .dockerignore | 8 + .github/workflows/ci-master-pr.yml | 74 ++++---- .vscode/launch.json | 2 - .vscode/settings.json | 1 + .vscode/tasks.json | 31 ++++ Dockerfile.asp-php => Dockerfile.asp | 34 +++- Dockerfile.asp-nginx | 18 -- ...file.bf2sclone-php => Dockerfile.bf2sclone | 26 ++- Dockerfile.bf2sclone-nginx | 18 -- README.md | 111 ++++++------ config/ASP/config.php | 40 ----- config/ASP/docker-entrypoint.sh | 94 ++++++++++ config/ASP/{ => etc}/nginx/nginx.conf | 9 +- config/ASP/php-fpm.d/www.conf | 10 -- config/ASP/supervisor.conf | 44 +++++ config/ASP/tail.sh | 11 ++ .../ASP/usr/local/etc/php-fpm.d/php-fpm.conf | 33 ++++ .../{ => usr/local/etc}/php/conf.d/php.ini | 0 .../python/bf2/BF2StatisticsConfig-custom.py | 2 +- config/bf2sclone/config.inc.php | 23 --- config/bf2sclone/docker-entrypoint.sh | 9 + .../bf2sclone/etc}/nginx/nginx.conf | 2 +- config/bf2sclone/nginx/nginx.conf | 118 ------------- config/bf2sclone/php-fpm.d/www.conf | 10 -- config/bf2sclone/supervisor.conf | 31 ++++ .../usr/local/etc/php-fpm.d/php-fpm.conf | 32 ++++ .../{ => usr/local/etc}/php/conf.d/php.ini | 0 docker-compose.build.yml | 30 +--- docker-compose.test.yml | 78 --------- docker-compose.yml | 133 +++++---------- docs/bf2hub-bf2stats-example/README.md | 48 +++--- .../config/ASP/config.php | 40 ----- .../config/ASP/nginx/nginx.conf | 127 -------------- .../config/ASP/php-fpm.d/www.conf | 10 -- .../config/ASP/php/conf.d/php.ini | 27 --- .../python/bf2/BF2StatisticsConfig-custom.py | 2 +- .../config/bf2sclone/config.inc.php | 23 --- .../config/bf2sclone/nginx/nginx.conf | 118 ------------- .../config/bf2sclone/php-fpm.d/www.conf | 10 -- .../config/bf2sclone/php/conf.d/php.ini | 27 --- .../docker-compose.build.yml | 21 +++ .../docker-compose.yml | 158 +++++++---------- docs/full-bf2-stack-example/README.md | 56 +++--- .../config/ASP/config.php | 40 ----- .../config/ASP/nginx/nginx.conf | 127 -------------- .../config/ASP/php-fpm.d/www.conf | 10 -- .../config/ASP/php/conf.d/php.ini | 27 --- .../bf2/settings/serversettings-custom.con | 2 +- .../python/bf2/BF2StatisticsConfig-custom.py | 2 +- .../config/bf2sclone/config.inc.php | 23 --- .../config/bf2sclone/php-fpm.d/www.conf | 10 -- .../config/bf2sclone/php/conf.d/php.ini | 27 --- .../docker-compose.build.yml | 21 +++ .../full-bf2-stack-example/docker-compose.yml | 160 +++++++----------- docs/upgrading-docker-images-to-2.6.md | 144 ++++++++++++++++ src/bf2sclone/config.inc.php | 30 +++- test/.env | 1 + test/docker-compose.yml | 35 ++++ .../snapshots/-dalian_plant_20231107_2013.txt | 1 + test/snapshots/-test-snapshot.txt | 1 + test/test-endpoints.sh | 77 +++++++++ test/test-external-dns.sh | 26 +++ test/test-internal-dns.sh | 24 +++ test/test-ready.sh | 20 +++ test/test-routes.sh | 53 ++++++ test/test-snapshots.sh | 19 +++ test/test.sh | 95 +++++++++++ 67 files changed, 1233 insertions(+), 1441 deletions(-) create mode 100644 .dockerignore create mode 100644 .vscode/tasks.json rename Dockerfile.asp-php => Dockerfile.asp (51%) delete mode 100644 Dockerfile.asp-nginx rename Dockerfile.bf2sclone-php => Dockerfile.bf2sclone (60%) delete mode 100644 Dockerfile.bf2sclone-nginx delete mode 100644 config/ASP/config.php create mode 100755 config/ASP/docker-entrypoint.sh rename config/ASP/{ => etc}/nginx/nginx.conf (95%) delete mode 100644 config/ASP/php-fpm.d/www.conf create mode 100644 config/ASP/supervisor.conf create mode 100755 config/ASP/tail.sh create mode 100644 config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf rename config/ASP/{ => usr/local/etc}/php/conf.d/php.ini (100%) delete mode 100644 config/bf2sclone/config.inc.php create mode 100644 config/bf2sclone/docker-entrypoint.sh rename {docs/full-bf2-stack-example/config/bf2sclone => config/bf2sclone/etc}/nginx/nginx.conf (98%) delete mode 100644 config/bf2sclone/nginx/nginx.conf delete mode 100644 config/bf2sclone/php-fpm.d/www.conf create mode 100644 config/bf2sclone/supervisor.conf create mode 100644 config/bf2sclone/usr/local/etc/php-fpm.d/php-fpm.conf rename config/bf2sclone/{ => usr/local/etc}/php/conf.d/php.ini (100%) delete mode 100644 docker-compose.test.yml delete mode 100644 docs/bf2hub-bf2stats-example/config/ASP/config.php delete mode 100644 docs/bf2hub-bf2stats-example/config/ASP/nginx/nginx.conf delete mode 100644 docs/bf2hub-bf2stats-example/config/ASP/php-fpm.d/www.conf delete mode 100644 docs/bf2hub-bf2stats-example/config/ASP/php/conf.d/php.ini delete mode 100644 docs/bf2hub-bf2stats-example/config/bf2sclone/config.inc.php delete mode 100644 docs/bf2hub-bf2stats-example/config/bf2sclone/nginx/nginx.conf delete mode 100644 docs/bf2hub-bf2stats-example/config/bf2sclone/php-fpm.d/www.conf delete mode 100644 docs/bf2hub-bf2stats-example/config/bf2sclone/php/conf.d/php.ini create mode 100644 docs/bf2hub-bf2stats-example/docker-compose.build.yml delete mode 100644 docs/full-bf2-stack-example/config/ASP/config.php delete mode 100644 docs/full-bf2-stack-example/config/ASP/nginx/nginx.conf delete mode 100644 docs/full-bf2-stack-example/config/ASP/php-fpm.d/www.conf delete mode 100644 docs/full-bf2-stack-example/config/ASP/php/conf.d/php.ini delete mode 100644 docs/full-bf2-stack-example/config/bf2sclone/config.inc.php delete mode 100644 docs/full-bf2-stack-example/config/bf2sclone/php-fpm.d/www.conf delete mode 100644 docs/full-bf2-stack-example/config/bf2sclone/php/conf.d/php.ini create mode 100644 docs/full-bf2-stack-example/docker-compose.build.yml create mode 100644 docs/upgrading-docker-images-to-2.6.md create mode 100644 test/.env create mode 100644 test/docker-compose.yml create mode 100644 test/snapshots/-dalian_plant_20231107_2013.txt create mode 100644 test/snapshots/-test-snapshot.txt create mode 100755 test/test-endpoints.sh create mode 100755 test/test-external-dns.sh create mode 100755 test/test-internal-dns.sh create mode 100755 test/test-ready.sh create mode 100755 test/test-routes.sh create mode 100755 test/test-snapshots.sh create mode 100755 test/test.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..723d65f8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +/.github +/.vscode +/docs +/src/python +/test +/Tools +/docker-compose.*.yml +/docker-compose.yml diff --git a/.github/workflows/ci-master-pr.yml b/.github/workflows/ci-master-pr.yml index 77264424..bb27bc30 100644 --- a/.github/workflows/ci-master-pr.yml +++ b/.github/workflows/ci-master-pr.yml @@ -16,49 +16,33 @@ jobs: matrix: testenv: - dev + - prod runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Cache Docker layers (asp-nginx) - uses: actions/cache@v3 - with: - path: /tmp/.buildx-asp-cache-nginx - key: ${{ runner.os }}-buildx-asp-nginx-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx-asp-nginx- - ${{ runner.os }}-buildx- - - - name: Cache Docker layers (asp-php) - uses: actions/cache@v3 - with: - path: /tmp/.buildx-cache-asp-php - key: ${{ runner.os }}-buildx-asp-php-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-buildx-asp-php- - ${{ runner.os }}-buildx- + # This is commented out, so we use the default 'docker' driver instead of the 'docker-container' driver. When using 'docker-container' driver, there appears to be a rate limit on writes on Github CI which causes buildx to fail with error code 17 when it is exporting to cache + # - name: Set up Docker Buildx + # id: buildx + # uses: docker/setup-buildx-action@v2 - - name: Cache Docker layers (bf2sclone-nginx) - uses: actions/cache@v3 + - name: Cache Docker layers (asp) + uses: actions/cache/restore@v3 # Restore cache but don't save it at end of job with: - path: /tmp/.buildx-bf2sclone-cache-nginx - key: ${{ runner.os }}-buildx-bf2sclone-nginx-${{ github.sha }} + path: /tmp/.buildx-cache-asp + key: ${{ runner.os }}-buildx-asp-${{ github.sha }} restore-keys: | - ${{ runner.os }}-buildx-bf2sclone-nginx- + ${{ runner.os }}-buildx-asp- ${{ runner.os }}-buildx- - - name: Cache Docker layers (bf2sclone-php) - uses: actions/cache@v3 + - name: Cache Docker layers (bf2sclone) + uses: actions/cache/restore@v3 # Restore cache but don't save it at end of job with: - path: /tmp/.buildx-cache-bf2sclone-php - key: ${{ runner.os }}-buildx-bf2sclone-php-${{ github.sha }} + path: /tmp/.buildx-cache-bf2sclone + key: ${{ runner.os }}-buildx-bf2sclone-${{ github.sha }} restore-keys: | - ${{ runner.os }}-buildx-bf2sclone-php- + ${{ runner.os }}-buildx-bf2sclone- ${{ runner.os }}-buildx- - name: Print buildx and compose @@ -71,17 +55,33 @@ jobs: if: matrix.testenv == 'dev' run: | set -eux - docker compose -f docker-compose.yml -f docker-compose.build.yml up --build -d - docker compose -f docker-compose.test.yml up + ./test/test.sh dev 1 1 + + - name: Integration test 1 (prod) + if: matrix.testenv == 'prod' + run: | + set -eux + ./test/test.sh prod1 1 1 + + - name: Integration test 2 (prod) + if: matrix.testenv == 'prod' + run: | + set -eux + + # Don't publish coredns ports to prevent conflict with system-resolved on github CI + # sed -i '$!N;s@ports:\n - 53:53.*@@;P;D' docker-compose.yml + + # Make coredns listen on localhost only to prevent conflict with system-resolved on github CI + sed -i 's/- 53:53/- 127.0.0.1:53:53/' docs/full-bf2-stack-example/docker-compose.yml + + ./test/test.sh prod2 1 1 build: strategy: matrix: variant: - - asp-nginx - - asp-php - - bf2sclone-nginx - - bf2sclone-php + - asp + - bf2sclone runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.vscode/launch.json b/.vscode/launch.json index 2eb64f88..cd549c2b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,8 +11,6 @@ "port": 9000, "pathMappings": { "/src": "${workspaceRoot}/src", - "/src/ASP/system/config/config.php": "${workspaceRoot}/config/ASP/config.php", - "/src/bf2sclone/config.inc.php": "${workspaceRoot}/config/bf2sclone/config.inc.php", }, "xdebugSettings": { "max_data": 10000, diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b7cd5c1..b5628c5e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,4 +5,5 @@ "*.con": "ini", "*.aspx": "php", }, + // "editor.trimAutoWhitespace": false } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..f0e2790c --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Test (dev)", + "type": "shell", + "command": "./test/test.sh dev 1", + "group": "build" + }, + { + "label": "Test (prod1)", + "type": "shell", + "command": "./test/test.sh prod 1", + "group": "build" + }, + { + "label": "Test (prod2)", + "type": "shell", + "command": "./test/test.sh prod 1", + "group": "build" + }, + { + "label": "Test (dns)", + "type": "shell", + "command": "./test/test.sh dns", + "group": "build" + }, + ] +} diff --git a/Dockerfile.asp-php b/Dockerfile.asp similarity index 51% rename from Dockerfile.asp-php rename to Dockerfile.asp index ac028089..f3e38301 100644 --- a/Dockerfile.asp-php +++ b/Dockerfile.asp @@ -10,6 +10,9 @@ RUN chown -R www-data:www-data . \ FROM $IMAGE AS dev +# Install nginx and supervisor for multi-process container +RUN apk add --no-cache ca-certificates nginx supervisor + # opcache RUN docker-php-ext-install opcache @@ -37,9 +40,34 @@ RUN set -eux; \ php -i; \ php -m -# Add default configs -COPY ./config/ASP/php/conf.d/php.ini /usr/local/etc/php/conf.d/php.ini -COPY ./config/ASP/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf +# Add configs +COPY ./config/ASP/. / +COPY ./src/ASP/system/config/config.php /config.sample/config.php +RUN set -eux; \ + chmod +x /docker-entrypoint.sh; \ + chmod +x /tail.sh; \ + # Symlink nginx logs + ln -sfn /dev/stdout /var/log/nginx/access.log; \ + ln -sfn /dev/stderr /var/log/nginx/error.log; \ + # Disable the built-in php-fpm configs, since we're using our own config + mv -v /usr/local/etc/php-fpm.d/docker.conf /usr/local/etc/php-fpm.d/docker.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf.disabled; + +# In docker, IPs may be dynamic. This ensures we get access +ENV ADMIN_HOSTS=0.0.0.0 +ENV ADMIN_BACKUP_PATH=/src/ASP/system/database/backups +# Authorize all gameservers within private IP ranges +ENV GAME_HOSTS=127.0.0.1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 +VOLUME /src/ASP/system/config +VOLUME /src/ASP/system/database/backups +VOLUME /src/ASP/system/logs +VOLUME /src/ASP/system/snapshots +EXPOSE 80 +EXPOSE 9000 +WORKDIR /src/ASP +ENTRYPOINT [] +CMD ["/docker-entrypoint.sh"] FROM dev AS prod diff --git a/Dockerfile.asp-nginx b/Dockerfile.asp-nginx deleted file mode 100644 index 27d9b8a8..00000000 --- a/Dockerfile.asp-nginx +++ /dev/null @@ -1,18 +0,0 @@ -ARG IMAGE=nginx:1.21-alpine -FROM $IMAGE AS build - -# Set permissions for 'nginx' user -COPY ./src/ASP /src/ASP -WORKDIR /src/ASP -RUN chown -R nginx:nginx . \ - && find . -type d -exec chmod 750 {} \; \ - && find . -type f -exec chmod 640 {} \; - -FROM $IMAGE AS dev - -# Add default configs -COPY config/ASP/nginx/nginx.conf /etc/nginx/nginx.conf - -FROM dev AS prod - -COPY --from=build /src /src diff --git a/Dockerfile.bf2sclone-php b/Dockerfile.bf2sclone similarity index 60% rename from Dockerfile.bf2sclone-php rename to Dockerfile.bf2sclone index b6c6e18b..e644722e 100644 --- a/Dockerfile.bf2sclone-php +++ b/Dockerfile.bf2sclone @@ -10,6 +10,9 @@ RUN chown -R www-data:www-data . \ FROM $IMAGE AS dev +# Install nginx and supervisor for multi-process container +RUN apk add --no-cache ca-certificates nginx supervisor + # opcache RUN docker-php-ext-install opcache @@ -19,7 +22,6 @@ RUN docker-php-ext-install pdo pdo_mysql # mysqli RUN docker-php-ext-install mysqli - # Xdebug: https://stackoverflow.com/questions/46825502/how-do-i-install-xdebug-on-dockers-official-php-fpm-alpine-image # PHPIZE_DEPS: autoconf dpkg-dev dpkg file g++ gcc libc-dev make pkgconf re2c RUN apk add --no-cache --virtual .build-dependencies $PHPIZE_DEPS \ @@ -41,9 +43,25 @@ RUN set -eux; \ php -i; \ php -m -# Add default configs -COPY ./config/bf2sclone/php/conf.d/php.ini /usr/local/etc/php/conf.d/php.ini -COPY ./config/bf2sclone/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf +# Add configs +COPY ./config/bf2sclone/. / +COPY ./src/bf2sclone/config.inc.php /config.inc.sample.php +RUN set -eux; \ + chmod +x /docker-entrypoint.sh; \ + # Symlink nginx logs + ln -sfn /dev/stdout /var/log/nginx/access.log; \ + ln -sfn /dev/stderr /var/log/nginx/error.log; \ + # Disable the built-in php-fpm configs, since we're using our own config + mv -v /usr/local/etc/php-fpm.d/docker.conf /usr/local/etc/php-fpm.d/docker.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/www.conf /usr/local/etc/php-fpm.d/www.conf.disabled; \ + mv -v /usr/local/etc/php-fpm.d/zz-docker.conf /usr/local/etc/php-fpm.d/zz-docker.conf.disabled; + +VOLUME /src/bf2sclone/cache +EXPOSE 80 +EXPOSE 9000 +WORKDIR /src/bf2sclone +ENTRYPOINT [] +CMD ["/docker-entrypoint.sh"] FROM dev AS prod diff --git a/Dockerfile.bf2sclone-nginx b/Dockerfile.bf2sclone-nginx deleted file mode 100644 index 9cec0198..00000000 --- a/Dockerfile.bf2sclone-nginx +++ /dev/null @@ -1,18 +0,0 @@ -ARG IMAGE=nginx:1.21-alpine -FROM $IMAGE AS build - -# Set permissions for 'nginx' user -COPY ./src/bf2sclone /src/bf2sclone -WORKDIR /src/bf2sclone -RUN chown -R nginx:nginx . \ - && find . -type d -exec chmod 750 {} \; \ - && find . -type f -exec chmod 640 {} \; - -FROM $IMAGE AS dev - -# Add default configs -COPY config/bf2sclone/nginx/nginx.conf /etc/nginx/nginx.conf - -FROM dev AS prod - -COPY --from=build /src /src diff --git a/README.md b/README.md index 27e7dde2..fd9552cb 100644 --- a/README.md +++ b/README.md @@ -2,32 +2,41 @@ [![github-actions](https://github.com/startersclan/bf2stats/workflows/ci-master-pr/badge.svg)](https://github.com/startersclan/bf2stats/actions) [![github-release](https://img.shields.io/github/v/release/startersclan/bf2stats?style=flat-square)](https://github.com/startersclan/bf2stats/releases/) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-asp-nginx?label=asp-nginx)](https://hub.docker.com/r/startersclan/asp) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-asp-php?label=asp-php)](https://hub.docker.com/r/startersclan/asp) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-bf2sclone-nginx?label=bf2sclone-nginx)](https://hub.docker.com/r/startersclan/asp) -[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-bf2sclone-php?label=bf2sclone-php)](https://hub.docker.com/r/startersclan/asp) +[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-asp?label=asp)](https://hub.docker.com/r/startersclan/bf2stats) +[![docker-image-size](https://img.shields.io/docker/image-size/startersclan/bf2stats/master-bf2sclone?label=bf2sclone)](https://hub.docker.com/r/startersclan/bf2stats) BF2Statistics [`2.x.x`](https://code.google.com/archive/p/bf2stats/) with docker support. Although BF2Statistics [`3.1.0`](https://github.com/BF2Statistics/ASP) has been released, it is not backward compatible with `<= 2.x.x`. Hence, this project is to help those who want to retain their `2.x.x` stats system, and to ease deployment of the stack since support is scarce. It runs on PHP 7.4 with nginx. -## Usage +## Usage (docker) + +`asp` image: + +```sh +docker run --rm -it -p 80:80 -e DB_HOST=db -e DB_PORT=3306 -e DB_NAME=bf2stats -e DB_USER=admin -e DB_PASS=admin startersclan/bf2stats:2.5.1-asp +``` + +`bf2sclone` image: ```sh -docker pull startersclan/bf2stats:2.5.1-asp-nginx -docker pull startersclan/bf2stats:2.5.1-asp-php -docker pull startersclan/bf2stats:2.5.1-bf2sclone-nginx -docker pull startersclan/bf2stats:2.5.1-bf2sclone-php +docker run --rm -it -p 80:80 -e DBIP=db -e DBNAME=bf2stats -e DBLOGIN=admin -e DBPASSWORD=admin startersclan/bf2stats:2.5.1-bf2sclone ``` See [this](docs/full-bf2-stack-example) example showing how to deploy [Battlefield 2 1.5 server](https://github.com/startersclan/docker-bf2/), [PRMasterserver](https://github.com/startersclan/PRMasterServer) as the master server, and `bf2stats` as the stats web server, using `docker-compose`. See [this](docs/bf2hub-bf2stats-example) example showing how to deploy [Battlefield 2 1.5 server](https://github.com/startersclan/docker-bf2/), with BF2Hub as the master server and `bf2stats` as the stats web server, using `docker-compose`. +### Upgrading + +See instructions to upgrade to v2.6.x [here](docs/upgrading-docker-images-to-2.6.md). + ## Development +To use Docker Compose v2, use `docker compose` instead of `docker-compose`. + ```sh -# 1. Start BF2 server, Gamespy server, and bf2stats +# 1. Start docker-compose up --build # ASP available at http://localhost:8081/ASP. Username: admin, password admin. Login and set up the DB the first time. See ./config/ASP/config.php # bf2sclone available at http://localhost:8082 @@ -70,30 +79,30 @@ docker-compose restart bf2 docker attach $( docker-compose ps -q bf2 ) # BF2 server - Exec into container docker exec -it $( docker-compose ps -q bf2) bash -# BF2 server - Read python logs +# BF2 server - Read logs docker exec -it $( docker-compose ps -q bf2 ) bash -c 'cat python/bf2/logs/bf2game_*' # BF2 server - List snapshots -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/sent' -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/unsent' - -# asp-php - Exec into container -docker exec -it $( docker-compose ps -q asp-php ) sh -# asp-php - Read logs -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/stats_debug.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_awards.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_ranks.log -# asp-php - List snapshots -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/processed -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/temp - -# Test routes -docker-compose -f docker-compose.test.yml up - -# Test production builds locally -docker build -t startersclan/bf2stats:asp-nginx -f Dockerfile.asp-nginx --target prod . -docker build -t startersclan/bf2stats:asp-php -f Dockerfile.asp-php --target prod . -docker build -t startersclan/bf2stats:bf2sclone-nginx -f Dockerfile.bf2sclone-nginx --target prod . -docker build -t startersclan/bf2stats:bf2sclone-php -f Dockerfile.bf2sclone-php --target prod . +docker exec -it $( docker-compose ps -q bf2 ) ls -alR python/bf2/logs/snapshots/unsent + +# asp - Exec into container +docker exec -it $( docker-compose ps -q asp ) sh +# asp - List backups +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/database/backups +# asp - List config +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/config +# asp - Read logs +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/logs +# asp - List snapshots +docker exec -it $( docker-compose ps -q asp ) ls -alR /src/ASP/system/snapshots + +# Test +./test/test.sh dev 1 + +# Test production builds 1 +./test/test.sh prod1 1 + +# Test production builds 2 +./test/test.sh prod2 1 # Dump the DB docker exec $( docker-compose ps -q db ) mysqldump -uroot -padmin bf2stats | gzip > bf2stats.sql.gz @@ -101,13 +110,14 @@ docker exec $( docker-compose ps -q db ) mysqldump -uroot -padmin bf2stats | gzi # Restore the DB zcat bf2stats.sql.gz | docker exec -i $( docker-compose ps -q db ) mysql -uroot -padmin bf2stats -# Stop BF2 server, gamespy server and bf2stats +# Stop docker-compose down # Cleanup -docker-compose down +docker-compose down --remove-orphans docker volume rm bf2stats_prmasterserver-volume docker volume rm bf2stats_backups-volume +docker volume rm bf2stats_config-volume docker volume rm bf2stats_logs-volume docker volume rm bf2stats_snapshots-volume docker volume rm bf2stats_bf2sclone-cache-volume @@ -132,21 +142,16 @@ git commit -m "Chore: Bump version to \`$TAG\`" A: This is caused by a bug where the UI fails to handle an invalid response from the backend. A `PHP_ERROR` `Warning: file_put_contents(/src/ASP/system/config/config.php): failed to open stream: Permission denied in /src/ASP/system/core/Config.php on line 165` is output before the JSON response causing invalid JSON. -Grant ASP `php`'s `www-data` user write permission for `config.php`. +Grant PHP write permission for `config.php`. ```sh chmod 666 ./config/ASP/config.php -docker-compose restart asp-php +docker-compose restart asp ``` ### Q: `Warning: file_put_contents(/src/ASP/system/config/config.php): failed to open stream: Permission denied in /src/ASP/system/core/Config.php on line 165` appearing in ASP dashboard -A: Grant ASP `php`'s `www-data` user write permission for `config.php`. - -```sh -chmod 666 ./config/ASP/config.php -docker-compose restart asp-php -``` +A: Grant the PHP user write permission for `./src/ASP/system/config/config.php`. ### Q: `There was an error testing the system. Please refresh the page and try again.` when using `System > Test System` in ASP @@ -154,19 +159,15 @@ A: This is means the UI received an invalid JSON response from the backend. If y ### Q: `BF2Statistics Processing Check: Fail` or ` Gamespy (.aspx) Basic Response: Fail` or `Gamespy (.aspx) Advanced (1) Response: Fail` when using `System > Test System` in ASP -A: DNS resolution problem. The `HOST` used in the test to test those Gamespy endpoints is the same host you see in your browser. For instance, if you are accessing the `ASP` using `http://localhost`, the `ASP` `php` container runs tests against `http://localhost/ASP/*.aspx`, which will fail, because the request is not going through `ASP` `nginx`. +A: DNS resolution problem. The `HOST` used in the test to test those Gamespy endpoints is the same host you see in your browser. For instance, if you are accessing the `ASP` using `http://yourdomain.com/`, `ASP` runs tests against `http://yourdomain.com/ASP/*.aspx`, which will may fail if DNS resolution for `yourdomain.com` fails. -If you see this in a development environment, simply ignore the errors. There is an integration test using [docker-compose.test.yml](docker-compose.test.yml) to test those endpoints to ensure they work. +If you see this in a development environment, simply ignore the errors. There is an integration test to those endpoints to ensure they work. -If you are seeing this in a production environment, use a fully qualified domain name (FQDN) so that `php` can resolve to its external DNS name to test against its external web endpoint. +If you are seeing this in a production environment, use a fully qualified domain name (FQDN) so that `ASP` can resolve to its external DNS name to test against its external web endpoint. ### Q: `Importing Logs Failed!` when using `Server Admin > Import Logs` in ASP -A: DNS resolution problem. The `HOST` used in the test to test those Gamespy endpoints is the same host you see in your browser. For instance, if you are accessing the `ASP` using `http://localhost`, the `ASP` `php` container runs tests against `http://localhost/ASP/*.aspx`, which will fail, because the request is not going through `ASP` `nginx`. - -If you see this in a development environment, simply ignore the errors. There is an integration test using [docker-compose.test.yml](docker-compose.test.yml) to test those endpoints to ensure they work. - -If you are seeing this in a production environment, use a fully qualified domain name (FQDN) so that `php` can resolve to its external DNS name to test against its external web endpoint. +A: Same as [this](#q-bf2statistics-processing-check-fail-or-gamespy-aspx-basic-response-fail-or-gamespy-aspx-advanced-1-response-fail-when-using-system--test-system-in-asp) ### Q: `Table (army) *NOT* Backed Up: [1045] Access denied for user 'admin'@'%' (using password: YES)` when using `System > Backup Database` in ASP @@ -174,15 +175,15 @@ A: The `db` user does not have the `FILE` privilege. Add a grant manually. But n ### Q: `Table (army) *NOT* Backed Up: [1] Can't create/write to file` when using `System > Backup Database` in ASP -The `backupdb` module uses [`SELECT * INTO OUTFILE`](https://mariadb.com/kb/en/select-into-outfile/), but the `src` files are not in the db container, `mariadb` cannot find the path to export the files. In the past, the `apache`, `php` and `mysql` ran on the same machine with write access to the same filesystem, but with `docker`, each container has its own filesystem. The only workaround is to mount the `backups-volume` inside the `db` container at the same path as it is mounted in the `ASP` `php` container `/src/ASP/system/database/backups/`, with write permissions for `php`'s user `82` and `mariadb`'s user `999` which menas the directory needs `777` permissions (world writeable), which is very bad from the point of view of security. +The `backupdb` module uses [`SELECT * INTO OUTFILE`](https://mariadb.com/kb/en/select-into-outfile/), but the `src` files are not in the db container, `mariadb` cannot find the path to export the files. In the past, the `apache`, `php` and `mysql` ran on the same machine with write access to the same filesystem, but with `docker`, each container has its own filesystem. The only workaround is to mount the `backups-volume` inside the `db` container at the same path as it is mounted in the `ASP` container `/src/ASP/system/database/backups/`, with write permissions for `php`'s user `82` and `mariadb`'s user `999` which menas the directory needs `777` permissions (world writeable), which is very bad from the point of view of security. It is better to backup the DB on a `cron` schedule using `mysqldump` from another container linked to the `db` container: ```sh -# Dump a DB at host `db`, user `root`, database `bf2stats` -mysqldump -hdb -uroot -p +# Dump a DB at host `db`, user `root`, password `admin`, database `bf2stats` +mysqldump -hdb -uroot -padmin bf2stats ``` -### Q: `Xdebug: [Step Debug] Could not connect to debugging client. Tried: host.docker.internal:9000 (through xdebug.client_host/xdebug.client_port)` appears in the php logs +### Q: `Xdebug: [Step Debug] Could not connect to debugging client. Tried: host.docker.internal:9000 (through xdebug.client_host/xdebug.client_port)` appears in PHP logs on `docker-compose up` -A: The debugger is not running. Press `F5` in `vscode` to start the `php` `xdebug` debugger. If you stopped the debugger, it is safe to ignore this message. +A: If you are seeing this in development, the PHP debugger is not running. Press `F5` in `vscode` to start the PHP debugger. If you don't need debugging, set `XDEBUG_MODE=off` in `docker-compose.yml` to disable XDebug. diff --git a/config/ASP/config.php b/config/ASP/config.php deleted file mode 100644 index 1c608b3b..00000000 --- a/config/ASP/config.php +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/config/ASP/docker-entrypoint.sh b/config/ASP/docker-entrypoint.sh new file mode 100755 index 00000000..5015507a --- /dev/null +++ b/config/ASP/docker-entrypoint.sh @@ -0,0 +1,94 @@ +#!/bin/sh +set -eu + +setup() { + local DIR="${1:?DIR is empty}" + local ALL="${2:-}" + mkdir -p "$DIR" + chown www-data:www-data "$DIR" + chmod 750 "$DIR" + if [ -n "$ALL" ]; then + chown -R www-data:www-data "$DIR" + find "$DIR" -type d -exec chmod 750 {} \; + find "$DIR" -type f -exec chmod 640 {} \; + fi +} + +echo "Setting permissions on backup volume" +setup /src/ASP/system/database/backups 1 + +echo "Setting up config file" +CONFIG_FILE_SAMPLE=/config.sample/config.php +CONFIG_FILE=/src/ASP/system/config/config.php +if [ ! -f "$CONFIG_FILE" ]; then + echo "Creating new config file: $CONFIG_FILE" + cp -v "$CONFIG_FILE_SAMPLE" "$CONFIG_FILE" +fi +echo "Setting permissions on config volume" +setup /src/ASP/system/config 1 + +echo "Setting permissions on logs volume" +setup /src/ASP/system/logs 1 + +# There can be many snapshots, and recursively setting permissions may be very slow +echo "Setting permissions on snapshots volume" +setup /src/ASP/system/snapshots +setup /src/ASP/system/snapshots/processed +setup /src/ASP/system/snapshots/temp + +write_config() { + # This function replaces config file values with env var values. E.g. DB_HOST=db sets $db_host = 'db' in config file + local KEY="${1:-}" + local TYPE="${2:-}" + local CONFIG_FILE="${3:-}" + if [ -z "$KEY" ]; then echo "KEY is empty"; exit 1; fi + if [ -z "$TYPE" ]; then echo "TYPE is empty"; exit 1; fi + if [ -z "$CONFIG_FILE" ]; then echo "CONFIG_FILE is empty"; exit 1; fi + + ENVVAR=$( echo "$KEY" | tr '[:lower:]' '[:upper:]' ) # E.g. 'db_host' to 'DB_HOST' + VAL=$( printenv "$ENVVAR" || true ) + if [ -n "$VAL" ]; then + echo "Writing key '$KEY' of type '$TYPE' to config file" + if [ "$TYPE" == 'string' ]; then + sed -i "s|^.$KEY =.*|\$$KEY = '$VAL';|" "$CONFIG_FILE" # E.g. $db_host = '127.0.0.1'; + elif [ "$TYPE" == 'int' ]; then + sed -i "s|^.$KEY =.*|\$$KEY = $VAL;|" "$CONFIG_FILE" # E.g. $db_port = 3306; + elif [ "$TYPE" == 'array' ]; then + # Values are comma-separated. E.g. 127.0.0.1,192.168.2.0/24,localhost,192.168.1.102,192.168.1.110,0.0.0.0 + # We need to make it a PHP string array + # set -x + VAL=$( echo "$VAL" | rev | sed 's/^,*//' | rev ) # Trim any trailing commas + VAL="array('$( echo "$VAL" | sed "s/,/','/g" )')" + sed -i "s|^.$KEY.*|\$$KEY = $VAL;|" "$CONFIG_FILE" # E.g. $admin_hosts = array('127.0.0.1','192.168.2.0/24','localhost','192.168.1.102','192.168.1.110','0.0.0.0'); + else + echo "Unsupported TYPE: $TYPE" + exit 1 + fi + else + echo "Not writing '$KEY' of type '$TYPE' to config file because env var '$ENVVAR' value is empty" + fi +} + +# Replace env var values in config file +CONFILE_FILE_CONTENT=$( cat "$CONFIG_FILE" ) +echo "$CONFILE_FILE_CONTENT" | grep -E '^\$' | while read -r KEY EQUALS VALUE; do + KEY=$( echo "$KEY" | sed 's/^\$//' ) # Strip the dollar sign. E.g. '$db_host' -> 'db_host' + VALUE=$( echo "$VALUE" | rev | sed 's/^;//' | rev ) # Strip the trailing semicolon + TYPE= + if echo "$VALUE" | grep -E "^'" > /dev/null; then + TYPE=string + elif echo "$VALUE" | grep -E "^array\(" > /dev/null; then + TYPE=array + elif echo "$VALUE" | grep -E "^[0-9]+$" > /dev/null; then + TYPE=int + else + echo "Unable to determine variable type of KEY '$KEY' in config file $CONFIG_FILE. Please check syntax." + exit 1 + fi + write_config "$KEY" "$TYPE" "$CONFIG_FILE" +done + +echo "Checking syntax of config file: $CONFIG_FILE" +php "$CONFIG_FILE" + +exec /usr/bin/supervisord -c /supervisor.conf --pidfile /run/supervisord.pid diff --git a/config/ASP/nginx/nginx.conf b/config/ASP/etc/nginx/nginx.conf similarity index 95% rename from config/ASP/nginx/nginx.conf rename to config/ASP/etc/nginx/nginx.conf index d615c4c9..8f084a3b 100644 --- a/config/ASP/nginx/nginx.conf +++ b/config/ASP/etc/nginx/nginx.conf @@ -52,6 +52,11 @@ http { set_real_ip_from 192.168.0.0/16; real_ip_header X-Real-IP; + # Redirect to /ASP + location = / { + return 301 /ASP/; + } + # We don't want to pass calls to css, script, and image files to the index, # whether they exist or not. So quit right here, and allow direct access # to common format files. Add formats here to allow direct link access @@ -96,7 +101,7 @@ http { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.aspx; - fastcgi_pass asp-php:9000; + fastcgi_pass 127.0.0.1:9000; } location ~ \.php$ { @@ -112,7 +117,7 @@ http { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; - fastcgi_pass asp-php:9000; + fastcgi_pass 127.0.0.1:9000; } location / { diff --git a/config/ASP/php-fpm.d/www.conf b/config/ASP/php-fpm.d/www.conf deleted file mode 100644 index eefbe39b..00000000 --- a/config/ASP/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php .aspx -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/config/ASP/supervisor.conf b/config/ASP/supervisor.conf new file mode 100644 index 00000000..a7e7d801 --- /dev/null +++ b/config/ASP/supervisor.conf @@ -0,0 +1,44 @@ +[supervisord] +nodaemon=true +user=root +logfile=/dev/null +logfile_maxbytes=0 + +[program:nginx] +command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;' +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:php-fpm] +command=php-fpm -F +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:tail] +command=/tail.sh +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/config/ASP/tail.sh b/config/ASP/tail.sh new file mode 100755 index 00000000..0bfe1e8b --- /dev/null +++ b/config/ASP/tail.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu +echo "Tailing logs in /src/ASP/system/logs/*.log" +tail -n0 -F \ + /src/ASP/system/logs/admin_event.log \ + /src/ASP/system/logs/merge_players.log \ + /src/ASP/system/logs/php_errors.log \ + /src/ASP/system/logs/stats_debug.log \ + /src/ASP/system/logs/validate_awards.log \ + /src/ASP/system/logs/validate_ranks.log \ + 2>/dev/null diff --git a/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf b/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf new file mode 100644 index 00000000..c01d475e --- /dev/null +++ b/config/ASP/usr/local/etc/php-fpm.d/php-fpm.conf @@ -0,0 +1,33 @@ +; Docs: https://www.php.net/manual/en/install.fpm.configuration.php +[global] +daemonize = no +error_log = /proc/self/fd/2 +; https://github.com/docker-library/php/pull/725#issuecomment-443540114 +log_limit = 8192 +log_buffering = no + +[default] +access.log = /proc/self/fd/2 +listen = 9000 +user = www-data +listen.owner = www-data +listen.group = www-data +pm = dynamic +pm.max_children = 10 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +pm.process_idle_timeout = 10s +pm.max_requests = 500 +; Enable php to read env vars +clear_env = no +catch_workers_output = yes +decorate_workers_output = no +chdir = / +pm.status_path = /status +; Allow .aspx extension +security.limit_extensions = .php .aspx +php_admin_value[log_errors] = On +php_admin_value[expose_php] = Off +php_admin_value[display_errors] = Off +php_admin_value[date.timezone] = UTC diff --git a/config/ASP/php/conf.d/php.ini b/config/ASP/usr/local/etc/php/conf.d/php.ini similarity index 100% rename from config/ASP/php/conf.d/php.ini rename to config/ASP/usr/local/etc/php/conf.d/php.ini diff --git a/config/bf2/python/bf2/BF2StatisticsConfig-custom.py b/config/bf2/python/bf2/BF2StatisticsConfig-custom.py index aa3c461b..e2c7cad6 100644 --- a/config/bf2/python/bf2/BF2StatisticsConfig-custom.py +++ b/config/bf2/python/bf2/BF2StatisticsConfig-custom.py @@ -16,7 +16,7 @@ # ------------------------------------------------------------------------------ # Backend Web Server # ------------------------------------------------------------------------------ -http_backend_addr = 'asp-nginx' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. +http_backend_addr = 'asp' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. http_backend_port = 80 http_backend_asp = '/ASP/bf2statistics.php' diff --git a/config/bf2sclone/config.inc.php b/config/bf2sclone/config.inc.php deleted file mode 100644 index 3bdf0dcd..00000000 --- a/config/bf2sclone/config.inc.php +++ /dev/null @@ -1,23 +0,0 @@ - default: 600 seconds (10 minutes) - -// Whether to hide bots from rankings -define ('RANKING_HIDE_BOTS', false); - -// Whether to hide hidden players from rankings -define ('RANKING_HIDE_HIDDEN_PLAYERS', false); - -// Number of players to show on the leaderboard frontpage -define ('LEADERBOARD_COUNT', 25); -?> diff --git a/config/bf2sclone/docker-entrypoint.sh b/config/bf2sclone/docker-entrypoint.sh new file mode 100644 index 00000000..823fd6b1 --- /dev/null +++ b/config/bf2sclone/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu + +echo "Setting permissions on cache volume" +chown -R www-data:www-data /src/bf2sclone/cache +find /src/bf2sclone/cache -type d -exec chmod 750 {} \; +find /src/bf2sclone/cache -type f -exec chmod 640 {} \; + +exec /usr/bin/supervisord -c /supervisor.conf --pidfile /run/supervisord.pid diff --git a/docs/full-bf2-stack-example/config/bf2sclone/nginx/nginx.conf b/config/bf2sclone/etc/nginx/nginx.conf similarity index 98% rename from docs/full-bf2-stack-example/config/bf2sclone/nginx/nginx.conf rename to config/bf2sclone/etc/nginx/nginx.conf index 89328305..e3f759d8 100644 --- a/docs/full-bf2-stack-example/config/bf2sclone/nginx/nginx.conf +++ b/config/bf2sclone/etc/nginx/nginx.conf @@ -103,7 +103,7 @@ http { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; - fastcgi_pass bf2sclone-php:9000; + fastcgi_pass 127.0.0.1:9000; } location / { diff --git a/config/bf2sclone/nginx/nginx.conf b/config/bf2sclone/nginx/nginx.conf deleted file mode 100644 index 89328305..00000000 --- a/config/bf2sclone/nginx/nginx.conf +++ /dev/null @@ -1,118 +0,0 @@ -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - - server { - listen 80; - # Ensure our redirects don't go to other ports, see https://serverfault.com/questions/351212/nginx-redirects-to-port-8080-when-accessing-url-without-slash - port_in_redirect off; - # Ensure our redirects are scheme-agnostic. Important behind a SSL-terminated load balancer. - absolute_redirect off; - - root /src/bf2sclone; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - index index.php index.html index.htm; - - # Increase upload max body size - client_max_body_size 1m; - client_body_buffer_size 1m; - - # Restore IP from Proxy - set_real_ip_from 127.0.0.0/8; - set_real_ip_from 10.0.0.0/8; - set_real_ip_from 172.16.0.0/12; - set_real_ip_from 192.168.0.0/16; - real_ip_header X-Real-IP; - - # We don't want to pass calls to css, script, and image files to the index, - # whether they exist or not. So quit right here, and allow direct access - # to common format files. Add formats here to allow direct link access - location ~ \.disabled$ { - return 401; - } - location ~ \.(gif|png|jpe?g|bmp|css|js|swf|wav|avi|mpg|ttf|woff|ico)$ { - # Show empty flag - location ~ (/game-images/armies)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/404.png =404; - } - # Show empty flag - location ~ (/game-images/flags)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/xx.png =404; - } - # Show empty flag - location ~ (/game-images/maps)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/map_NA.jpg =404; - } - - access_log off; - add_header Cache-Control "public, s-maxage=600, maxage=600"; - try_files $uri =404; - } - - # Deny access to hidden files - location ~ /\.[^/]+$ { - return 401; - } - # Deny access to certain files - location ~ \.inc.php$ { - return 401; - } - # Deny access certain directories - location ~ ^/(cache|queries|template) { - return 401; - } - - location ~ \.php$ { - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 5s; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.php; - fastcgi_pass bf2sclone-php:9000; - } - - location / { - limit_except GET POST { - deny all; - } - - # Pass everything else to php - try_files $uri $uri/ index.php?$args; - } - } -} diff --git a/config/bf2sclone/php-fpm.d/www.conf b/config/bf2sclone/php-fpm.d/www.conf deleted file mode 100644 index b931b2cf..00000000 --- a/config/bf2sclone/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/config/bf2sclone/supervisor.conf b/config/bf2sclone/supervisor.conf new file mode 100644 index 00000000..26409e23 --- /dev/null +++ b/config/bf2sclone/supervisor.conf @@ -0,0 +1,31 @@ +[supervisord] +nodaemon=true +user=root +logfile=/dev/null +logfile_maxbytes=0 + +[program:nginx] +command=nginx -c /etc/nginx/nginx.conf -g 'daemon off;' +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:php-fpm] +command=php-fpm -F +process_name=%(program_name)s_%(process_num)02d +user=root +numprocs=1 +autostart=true +autorestart=false +startsecs=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/config/bf2sclone/usr/local/etc/php-fpm.d/php-fpm.conf b/config/bf2sclone/usr/local/etc/php-fpm.d/php-fpm.conf new file mode 100644 index 00000000..f30ff066 --- /dev/null +++ b/config/bf2sclone/usr/local/etc/php-fpm.d/php-fpm.conf @@ -0,0 +1,32 @@ +; Docs: https://www.php.net/manual/en/install.fpm.configuration.php +[global] +daemonize = no +error_log = /proc/self/fd/2 +; https://github.com/docker-library/php/pull/725#issuecomment-443540114 +log_limit = 8192 +log_buffering = no + +[default] +access.log = /proc/self/fd/2 +listen = 9000 +user = www-data +listen.owner = www-data +listen.group = www-data +pm = dynamic +pm.max_children = 10 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +pm.process_idle_timeout = 10s +pm.max_requests = 500 +; Enable php to read env vars +clear_env = no +catch_workers_output = yes +decorate_workers_output = no +chdir = / +pm.status_path = /status +security.limit_extensions = .php +php_admin_value[log_errors] = On +php_admin_value[expose_php] = Off +php_admin_value[display_errors] = Off +php_admin_value[date.timezone] = UTC diff --git a/config/bf2sclone/php/conf.d/php.ini b/config/bf2sclone/usr/local/etc/php/conf.d/php.ini similarity index 100% rename from config/bf2sclone/php/conf.d/php.ini rename to config/bf2sclone/usr/local/etc/php/conf.d/php.ini diff --git a/docker-compose.build.yml b/docker-compose.build.yml index 5d5766dc..faebbe9a 100644 --- a/docker-compose.build.yml +++ b/docker-compose.build.yml @@ -1,29 +1,15 @@ # This is a docker compose override file, for development builds with caching for CI environments services: - asp-nginx: + asp: build: cache_from: - - type=local,src=/tmp/.buildx-cache-web - cache_to: - - type=local,dest=/tmp/.buildx-cache-web,mode=max + - type=local,src=/tmp/.buildx-cache-asp + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-asp,mode=max - asp-php: + bf2sclone: build: cache_from: - - type=local,src=/tmp/.buildx-cache-php - cache_to: - - type=local,dest=/tmp/.buildx-cache-php,mode=max - - bf2sclone-nginx: - build: - cache_from: - - type=local,src=/tmp/.buildx-cache-web - cache_to: - - type=local,dest=/tmp/.buildx-cache-web,mode=max - - bf2sclone-php: - build: - cache_from: - - type=local,src=/tmp/.buildx-cache-php - cache_to: - - type=local,dest=/tmp/.buildx-cache-php,mode=max + - type=local,src=/tmp/.buildx-cache-bf2sclone + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-bf2sclone,mode=max diff --git a/docker-compose.test.yml b/docker-compose.test.yml deleted file mode 100644 index 1193327c..00000000 --- a/docker-compose.test.yml +++ /dev/null @@ -1,78 +0,0 @@ -version: '2.2' -services: - test-routes: - image: alpine:latest - environment: - URLS: | - http://asp-nginx/ 403 - http://asp-nginx/.htaccess 401 - http://asp-nginx/ASP/ 200 - http://asp-nginx/ASP/frontend/template.php 401 - http://asp-nginx/ASP/frontend/css/reset.css 200 - http://asp-nginx/ASP/frontend/js/jquery-ui.js 200 - http://asp-nginx/ASP/frontend/images/bf2logo.png 200 - http://asp-nginx/ASP/frontend/css/fonts/ptsans/PTS55F-webfont.woff 200 - http://asp-nginx/ASP/system 401 - http://asp-nginx/ASP/bf2statistics.php 200 - http://asp-nginx/ASP/getawardsinfo.aspx 200 - http://asp-nginx/ASP/getbackendinfo.aspx 200 - http://asp-nginx/ASP/getclaninfo.aspx 200 - http://asp-nginx/ASP/getleaderboard.aspx 200 - http://asp-nginx/ASP/getmapinfo.aspx 200 - http://asp-nginx/ASP/getplayerid.aspx 200 - http://asp-nginx/ASP/getplayerinfo.aspx 200 - http://asp-nginx/ASP/getrankinfo.aspx 200 - http://asp-nginx/ASP/getunlocksinfo.aspx 200 - http://asp-nginx/ASP/index.php 200 - http://asp-nginx/ASP/ranknotification.aspx 200 - http://asp-nginx/ASP/searchforplayers.aspx 200 - http://asp-nginx/ASP/selectunlock.aspx 200 - http://bf2sclone-nginx/ 200 - http://bf2sclone-nginx/.htaccess 401 - http://bf2sclone-nginx/cache 401 - http://bf2sclone-nginx/css/default.css 200 - http://bf2sclone-nginx/game-images/armies/0.png 200 - http://bf2sclone-nginx/js/nt2.js 200 - http://bf2sclone-nginx/queries/armies.list 401 - http://bf2sclone-nginx/queries/getArmiesByPID.php 401 - http://bf2sclone-nginx/site-images/online.png 200 - http://bf2sclone-nginx/template/config.inc.php.template 401 - http://bf2sclone-nginx/awards.inc.php 401 - http://bf2sclone-nginx/install.php.disabled 401 - networks: - - bf2-network - entrypoint: - - /bin/sh - command: - - -c - - | - set -eu - - echo "Waiting for stack to be ready" - s=0 - while true; do - nc -vz -w 1 asp-nginx 80 \ - && nc -vz -w 1 asp-php 9000 \ - && nc -vz -w 1 bf2sclone-nginx 80 \ - && nc -vz -w 1 bf2sclone-php 9000 \ - && nc -vz -w 1 db 3306 \ - && break || true - s=$$(( $$s + 1 )) - if [ "$$s" -eq 600 ]; then - exit 1 - fi - echo "Retrying in 3 seconds" - sleep 3 - done - - echo "$$URLS" | awk NF | while read -r i j; do - if wget -q -SO- "$$i" 2>&1 | grep "HTTP/1.1 $$j " > /dev/null; then - echo "PASS: $$i" - else - echo "FAIL: $$i" - exit 1 - fi - done - -networks: - bf2-network: diff --git a/docker-compose.yml b/docker-compose.yml index f60294ec..4a1326e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - ./config/bf2/mods/bf2/settings/serversettings-custom.con:/server/bf2/mods/bf2/settings/serversettings.con:ro # Server config - ./config/bf2/mods/bf2/settings/maplist-custom-coop.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist (coop) # - ./config/bf2/mods/bf2/settings/maplist-custom-cq.con:/server/bf2/mods/bf2/settings/maplist.con:ro # Maplist (cq) - - ./src/python:/server/bf2/python + - ./src/python:/server/bf2/python # Mount the python files - ./config/bf2/python/bf2/BF2StatisticsConfig-custom.py:/server/bf2/python/bf2/BF2StatisticsConfig.py:ro # bf2stats python config ports: - 16567:16567/udp @@ -17,8 +17,7 @@ services: - bf2-network - gamespy-network depends_on: - - asp-nginx - - asp-php + - asp tty: true stdin_open: true @@ -72,12 +71,6 @@ services: image: alpine:latest volumes: - ./src:/src - - ./config/ASP/config.php:/src/ASP/system/config/config.php - - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php - - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - - bf2sclone-cache-volume:/src/bf2sclone/cache - db-volume:/var/lib/mysql entrypoint: - /bin/sh @@ -86,44 +79,12 @@ services: - | set -eu - echo "Granting ASP nginx and php read permissions" - find /src/ASP -type d -exec chmod 755 {} \; - find /src/ASP -type f -exec chmod 644 {} \; - - echo "Granting ASP php write permissions" - chmod 777 /src/ASP/system/config - chmod 666 /src/ASP/system/config/config.php - chmod 666 /src/ASP/system/config/config.php.bak || true - - chown -R 82:82 /src/ASP/system/database/backups - find /src/ASP/system/database/backups -type d -exec chmod 750 {} \; - find /src/ASP/system/database/backups -type f -exec chmod 640 {} \; - - chown -R 82:82 /src/ASP/system/logs - find /src/ASP/system/logs -type d -exec chmod 750 {} \; - find /src/ASP/system/logs -type f -exec chmod 640 {} \; - - mkdir -p /src/ASP/system/snapshots/processed - mkdir -p /src/ASP/system/snapshots/temp - chown -R 82:82 /src/ASP/system/snapshots - find /src/ASP/system/snapshots -type d -exec chmod 750 {} \; - find /src/ASP/system/snapshots -type f -exec chmod 640 {} \; - - echo "Granting bf2sclone nginx and php read permissions" - find /src/bf2sclone -type d -exec chmod 755 {} \; - find /src/bf2sclone -type f -exec chmod 644 {} \; - - echo "Granting bf2sclone php write permissions" - chown -R 82:82 /src/bf2sclone/cache - find /src/bf2sclone/cache -type d -exec chmod 750 {} \; - find /src/bf2sclone/cache -type f -exec chmod 640 {} \; - echo "Granting db write permissions" chown -R 999:999 /var/lib/mysql - asp-nginx: + asp: build: - dockerfile: Dockerfile.asp-nginx + dockerfile: Dockerfile.asp context: . target: dev labels: @@ -133,82 +94,63 @@ services: # http - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.entrypoints=web" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.rule=Host(`bf2web.gamespy.com`)" # Note: `bf2web.gamespy.com` doesn't need https. The BF2 client BFHQ makes a HTTP requests to `bf2web.gamespy.com` with `Host: bf2web.gamespy.com`. + environment: + # - XDEBUG_MODE=off # Uncomment to disable xdebug + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=admin + - DB_PASS=admin volumes: - - ./src:/src:ro - - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./src/ASP:/src/ASP + - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - config-volume:/src/ASP/system/config # For a stateful config file + - logs-volume:/src/ASP/system/logs + - snapshots-volume:/src/ASP/system/snapshots ports: - 8081:80 + - 9000 networks: traefik-network: - # Spoof gamespy DNS for the BF2 server connected to this network bf2-network: aliases: - - bf2web.gamespy.com - - gamestats.gamespy.com # Unused - - eapusher.dice.se # Unused - depends_on: - - init-container - - asp-php - working_dir: /src - - asp-php: - build: - dockerfile: Dockerfile.asp-php - context: . - target: dev - volumes: - - ./src/ASP:/src/ASP - - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize as needed - # - ./config/ASP/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro - # - ./config/ASP/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro - - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - networks: - - bf2-network + - bf2web.gamespy.com # Spoof gamespy DNS for the BF2 server connected to this network extra_hosts: # For xdebug to reach the host via `host.docker.internal`. See: https://github.com/moby/moby/pull/40007#issuecomment-578729356 and https://stackoverflow.com/questions/49907308/installing-xdebug-in-docker # If xdebug does not work, you may need to add an iptables rule to the INPUT chain: iptables -A INPUT -i br+ -j ACCEPT - host.docker.internal:host-gateway - depends_on: - - init-container - - bf2sclone-nginx: - build: - dockerfile: Dockerfile.bf2sclone-nginx - context: . - target: dev - volumes: - - ./src/bf2sclone:/src/bf2sclone:ro - - ./config/bf2sclone/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - ports: - - 8082:80 - networks: - - bf2-network - depends_on: - - init-container - - bf2sclone-php - working_dir: /src - bf2sclone-php: + bf2sclone: build: - dockerfile: Dockerfile.bf2sclone-php + dockerfile: Dockerfile.bf2sclone context: . target: dev volumes: - ./src/bf2sclone:/src/bf2sclone - - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php:ro # Main config file. Customize as needed - # - ./config/bf2sclone/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro - # - ./config/bf2sclone/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro - bf2sclone-cache-volume:/src/bf2sclone/cache + environment: + # - XDEBUG_MODE=off # Uncomment to disable xdebug + # See ./src/bf2sclone/config.inc.php for all supported env vars + - DBIP=db + - DBNAME=bf2stats + - DBLOGIN=admin + - DBPASSWORD=admin + # - TITLE=BF2S Clone + - RANKING_REFRESH_TIME=0 + # - RANKING_HIDE_BOTS=false + # - RANKING_HIDE_HIDDEN_PLAYERS=false + # - LEADERBOARD_COUNT=25 + ports: + - 8082:80 + - 9000 networks: + - traefik-network - bf2-network extra_hosts: # For xdebug to reach the host via `host.docker.internal`. See: https://github.com/moby/moby/pull/40007#issuecomment-578729356 and https://stackoverflow.com/questions/49907308/installing-xdebug-in-docker # If xdebug does not work, you may need to add an iptables rule to the INPUT chain: iptables -A INPUT -i br+ -j ACCEPT - host.docker.internal:host-gateway - depends_on: - - init-container db: image: mariadb:10.8 @@ -244,6 +186,7 @@ networks: volumes: prmasterserver-volume: backups-volume: + config-volume: logs-volume: snapshots-volume: bf2sclone-cache-volume: diff --git a/docs/bf2hub-bf2stats-example/README.md b/docs/bf2hub-bf2stats-example/README.md index 9cef9280..becca1a9 100644 --- a/docs/bf2hub-bf2stats-example/README.md +++ b/docs/bf2hub-bf2stats-example/README.md @@ -29,17 +29,15 @@ You should see something like: ```sh $ docker-compose up -[+] Running 10/0 - ⠿ Container bf2stats-phpmyadmin-1 Running 0.0s - ⠿ Container bf2stats-bf2-1 Running 0.0s - ⠿ Container bf2stats-traefik-1 Running 0.0s - ⠿ Container bf2stats-init-container-1 Created 0.0s - ⠿ Container bf2stats-db-1 Running 0.0s - ⠿ Container bf2stats-asp-php-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-php-1 Running 0.0s - ⠿ Container bf2stats-asp-nginx-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-nginx-1 Running 0.0s -Attaching to bf2stats-asp-nginx-1, bf2stats-asp-php-1, bf2stats-bf2-1, bf2stats-bf2sclone-nginx-1, bf2stats-bf2sclone-php-1, bf2stats-coredns-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-traefik-1 +[+] Running 7/7 + ✔ Container bf2stats-bf2sclone-1 Running 0.1s + ✔ Container bf2stats-phpmyadmin-1 Running 0.0s + ✔ Container bf2stats-init-container-1 Running 0.0s + ✔ Container bf2stats-traefik-1 Running 0.0s + ✔ Container bf2stats-asp-1 Running 0.1s + ✔ Container bf2stats-db-1 Running 0.1s + ✔ Container bf2stats-bf2-1 Running 0.0s +Attaching to bf2stats-asp-1, bf2stats-bf2-1, bf2stats-bf2sclone-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-traefik-1 0.0s ``` The stack is now running: @@ -113,21 +111,21 @@ docker-compose restart bf2 docker attach $( docker-compose ps -q bf2 ) # BF2 server - Exec into container docker exec -it $( docker-compose ps -q bf2) bash -# BF2 server - Read python logs +# BF2 server - Read logs docker exec -it $( docker-compose ps -q bf2 ) bash -c 'cat python/bf2/logs/bf2game_*' # BF2 server - List snapshots -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/sent' -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/unsent' - -# asp-php - Exec into container -docker exec -it $( docker-compose ps -q asp-php ) sh -# asp-php - Read logs -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/stats_debug.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_awards.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_ranks.log -# asp-php - List snapshots -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/processed -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/temp +docker exec -it $( docker-compose ps -q bf2 ) ls -alR python/bf2/logs/snapshots/unsent + +# asp - Exec into container +docker exec -it $( docker-compose ps -q asp ) sh +# asp - List backups +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/database/backups +# asp - List config +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/config +# asp - Read logs +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/logs +# asp - List snapshots +docker exec -it $( docker-compose ps -q asp ) ls -alR /src/ASP/system/snapshots # Dump the DB docker exec $( docker-compose ps -q db ) mysqldump -uroot -padmin bf2stats | gzip > bf2stats.sql.gz @@ -139,7 +137,7 @@ zcat bf2stats.sql.gz | docker exec -i $( docker-compose ps -q db ) mysql -uroot docker-compose down # Cleanup. Warning: This destroys the all data! -docker-compose down +docker-compose down --remove-orphans docker volume rm bf2stats_prmasterserver-volume docker volume rm bf2stats_traefik-acme-volume docker volume rm bf2stats_backups-volume diff --git a/docs/bf2hub-bf2stats-example/config/ASP/config.php b/docs/bf2hub-bf2stats-example/config/ASP/config.php deleted file mode 100644 index 01422fe1..00000000 --- a/docs/bf2hub-bf2stats-example/config/ASP/config.php +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/docs/bf2hub-bf2stats-example/config/ASP/nginx/nginx.conf b/docs/bf2hub-bf2stats-example/config/ASP/nginx/nginx.conf deleted file mode 100644 index d615c4c9..00000000 --- a/docs/bf2hub-bf2stats-example/config/ASP/nginx/nginx.conf +++ /dev/null @@ -1,127 +0,0 @@ -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - - server { - listen 80; - # Ensure our redirects don't go to other ports, see https://serverfault.com/questions/351212/nginx-redirects-to-port-8080-when-accessing-url-without-slash - port_in_redirect off; - # Ensure our redirects are scheme-agnostic. Important behind a SSL-terminated load balancer. - absolute_redirect off; - - root /src; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - index index.php index.html index.htm; - - # Increase upload max body size - client_max_body_size 5m; - client_body_buffer_size 5m; - - # Restore IP from Proxy - set_real_ip_from 127.0.0.0/8; - set_real_ip_from 10.0.0.0/8; - set_real_ip_from 172.16.0.0/12; - set_real_ip_from 192.168.0.0/16; - real_ip_header X-Real-IP; - - # We don't want to pass calls to css, script, and image files to the index, - # whether they exist or not. So quit right here, and allow direct access - # to common format files. Add formats here to allow direct link access - location ~ \.(gif|png|jpe?g|bmp|css|js|swf|wav|avi|mpg|ttf|woff|ico)$ { - # Show empty flag - location ~ (/ASP/frontend/images/flags)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/xx.png =404; - } - - access_log off; - add_header Cache-Control "public, s-maxage=600, maxage=600"; - try_files $uri =404; - } - - # Deny access to hidden files - location ~ /\.[^/]+$ { - return 401; - } - # Deny access to the frontend and system folders. All defined - # file extensions from the previous rewrite rule wont make it here, which allows - # direct access to images and such in these folders still. - location ~ ^/ASP/(frontend|system) { - return 401; - } - - # Pass .aspx to php - location ~ \.aspx$ { - add_header Cache-Control "public, s-maxage=0, maxage=0"; - - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Turn off chunked transfer encoding in HTTP/1.1. Older BF2 client or server python files may not be able to handle it - chunked_transfer_encoding off; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 10s; - fastcgi_split_path_info ^(.+\.aspx)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.aspx; - fastcgi_pass asp-php:9000; - } - - location ~ \.php$ { - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 3600s; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.php; - fastcgi_pass asp-php:9000; - } - - location / { - limit_except GET POST { - deny all; - } - - # Pass everything else to php - try_files $uri $uri/ =404; - } - } -} diff --git a/docs/bf2hub-bf2stats-example/config/ASP/php-fpm.d/www.conf b/docs/bf2hub-bf2stats-example/config/ASP/php-fpm.d/www.conf deleted file mode 100644 index eefbe39b..00000000 --- a/docs/bf2hub-bf2stats-example/config/ASP/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php .aspx -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/docs/bf2hub-bf2stats-example/config/ASP/php/conf.d/php.ini b/docs/bf2hub-bf2stats-example/config/ASP/php/conf.d/php.ini deleted file mode 100644 index a79c6f23..00000000 --- a/docs/bf2hub-bf2stats-example/config/ASP/php/conf.d/php.ini +++ /dev/null @@ -1,27 +0,0 @@ -[hardening] -disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file -cgi.fix_pathinfo = 0 -cgi.force_redirect = 1 -allow_url_fopen = 0 -allow_url_include = 0 -expose_php = 0 - -open_basedir = /src:/tmp -upload_tmp_dir = /tmp - -display_errors = 0 -log_errors = 1 -error_reporting = E_ALL -ignore_repeated_errors = 1 -#error_log = /var/lib/php/logs/error.log - -max_execution_time = 35 -max_input_time = 35 -file_uploads = 1 -post_max_size = 5M -upload_max_filesize = 5M - -[opcache] -opcache.enable=1 -opcache.memory_consumption = 64 -opcache.fast_shutdown = 0 diff --git a/docs/bf2hub-bf2stats-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py b/docs/bf2hub-bf2stats-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py index 302e8c52..98171eb6 100644 --- a/docs/bf2hub-bf2stats-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py +++ b/docs/bf2hub-bf2stats-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py @@ -16,7 +16,7 @@ # ------------------------------------------------------------------------------ # Backend Web Server # ------------------------------------------------------------------------------ -http_backend_addr = 'asp-nginx' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. +http_backend_addr = 'asp' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. http_backend_port = 80 http_backend_asp = '/ASP/bf2statistics.php' diff --git a/docs/bf2hub-bf2stats-example/config/bf2sclone/config.inc.php b/docs/bf2hub-bf2stats-example/config/bf2sclone/config.inc.php deleted file mode 100644 index 04226f2e..00000000 --- a/docs/bf2hub-bf2stats-example/config/bf2sclone/config.inc.php +++ /dev/null @@ -1,23 +0,0 @@ - default: 600 seconds (10 minutes) - -// Whether to hide bots from rankings -define ('RANKING_HIDE_BOTS', false); - -// Whether to hide hidden players from rankings -define ('RANKING_HIDE_HIDDEN_PLAYERS', false); - -// Number of players to show on the leaderboard frontpage -define ('LEADERBOARD_COUNT', 25); -?> diff --git a/docs/bf2hub-bf2stats-example/config/bf2sclone/nginx/nginx.conf b/docs/bf2hub-bf2stats-example/config/bf2sclone/nginx/nginx.conf deleted file mode 100644 index 89328305..00000000 --- a/docs/bf2hub-bf2stats-example/config/bf2sclone/nginx/nginx.conf +++ /dev/null @@ -1,118 +0,0 @@ -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - - server { - listen 80; - # Ensure our redirects don't go to other ports, see https://serverfault.com/questions/351212/nginx-redirects-to-port-8080-when-accessing-url-without-slash - port_in_redirect off; - # Ensure our redirects are scheme-agnostic. Important behind a SSL-terminated load balancer. - absolute_redirect off; - - root /src/bf2sclone; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - index index.php index.html index.htm; - - # Increase upload max body size - client_max_body_size 1m; - client_body_buffer_size 1m; - - # Restore IP from Proxy - set_real_ip_from 127.0.0.0/8; - set_real_ip_from 10.0.0.0/8; - set_real_ip_from 172.16.0.0/12; - set_real_ip_from 192.168.0.0/16; - real_ip_header X-Real-IP; - - # We don't want to pass calls to css, script, and image files to the index, - # whether they exist or not. So quit right here, and allow direct access - # to common format files. Add formats here to allow direct link access - location ~ \.disabled$ { - return 401; - } - location ~ \.(gif|png|jpe?g|bmp|css|js|swf|wav|avi|mpg|ttf|woff|ico)$ { - # Show empty flag - location ~ (/game-images/armies)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/404.png =404; - } - # Show empty flag - location ~ (/game-images/flags)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/xx.png =404; - } - # Show empty flag - location ~ (/game-images/maps)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/map_NA.jpg =404; - } - - access_log off; - add_header Cache-Control "public, s-maxage=600, maxage=600"; - try_files $uri =404; - } - - # Deny access to hidden files - location ~ /\.[^/]+$ { - return 401; - } - # Deny access to certain files - location ~ \.inc.php$ { - return 401; - } - # Deny access certain directories - location ~ ^/(cache|queries|template) { - return 401; - } - - location ~ \.php$ { - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 5s; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.php; - fastcgi_pass bf2sclone-php:9000; - } - - location / { - limit_except GET POST { - deny all; - } - - # Pass everything else to php - try_files $uri $uri/ index.php?$args; - } - } -} diff --git a/docs/bf2hub-bf2stats-example/config/bf2sclone/php-fpm.d/www.conf b/docs/bf2hub-bf2stats-example/config/bf2sclone/php-fpm.d/www.conf deleted file mode 100644 index b931b2cf..00000000 --- a/docs/bf2hub-bf2stats-example/config/bf2sclone/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/docs/bf2hub-bf2stats-example/config/bf2sclone/php/conf.d/php.ini b/docs/bf2hub-bf2stats-example/config/bf2sclone/php/conf.d/php.ini deleted file mode 100644 index a79c6f23..00000000 --- a/docs/bf2hub-bf2stats-example/config/bf2sclone/php/conf.d/php.ini +++ /dev/null @@ -1,27 +0,0 @@ -[hardening] -disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file -cgi.fix_pathinfo = 0 -cgi.force_redirect = 1 -allow_url_fopen = 0 -allow_url_include = 0 -expose_php = 0 - -open_basedir = /src:/tmp -upload_tmp_dir = /tmp - -display_errors = 0 -log_errors = 1 -error_reporting = E_ALL -ignore_repeated_errors = 1 -#error_log = /var/lib/php/logs/error.log - -max_execution_time = 35 -max_input_time = 35 -file_uploads = 1 -post_max_size = 5M -upload_max_filesize = 5M - -[opcache] -opcache.enable=1 -opcache.memory_consumption = 64 -opcache.fast_shutdown = 0 diff --git a/docs/bf2hub-bf2stats-example/docker-compose.build.yml b/docs/bf2hub-bf2stats-example/docker-compose.build.yml new file mode 100644 index 00000000..9b6e5700 --- /dev/null +++ b/docs/bf2hub-bf2stats-example/docker-compose.build.yml @@ -0,0 +1,21 @@ +# This is a docker compose override file, for production builds with caching for CI environments +services: + asp: + build: + dockerfile: Dockerfile.asp + context: ../../ + target: prod + cache_from: + - type=local,src=/tmp/.buildx-cache-asp + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-asp,mode=max + + bf2sclone: + build: + dockerfile: Dockerfile.bf2sclone + context: ../../ + target: prod + cache_from: + - type=local,src=/tmp/.buildx-cache-bf2sclone + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-bf2sclone,mode=max diff --git a/docs/bf2hub-bf2stats-example/docker-compose.yml b/docs/bf2hub-bf2stats-example/docker-compose.yml index 38293743..c3ba94ea 100644 --- a/docs/bf2hub-bf2stats-example/docker-compose.yml +++ b/docs/bf2hub-bf2stats-example/docker-compose.yml @@ -27,8 +27,7 @@ services: # - gamestats.gamespy.com:192.168.1.100 # Our ASP web server IP. Use this if the ASP web server is running on a different host. # - eapusher.dice.se:192.168.1.100 # Our ASP web server IP. Use this if the ASP web server is running on a different host. depends_on: - - asp-nginx - - asp-php + - asp restart: unless-stopped tty: true stdin_open: true @@ -45,6 +44,7 @@ services: ports: - 80:80 - 443:443 + # - 8080:8080 # Uncomment to view traefik dashboard on port 8080 networks: - traefik-public-network - traefik-network @@ -52,6 +52,7 @@ services: command: - --global.checknewversion=false - --global.sendanonymoususage=false + # - --api.insecure # Uncomment to view traefik dashboard on port 8080 # - --log.level=DEBUG - --providers.docker=true - --providers.docker.exposedbydefault=false @@ -63,15 +64,10 @@ services: - --certificatesresolvers.myresolver.acme.email=postmaster@example.com - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json - # The init container that sets up permissions for the asp and db volumes + # The init container that sets up permissions init-container: image: alpine:latest volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php - - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - - bf2sclone-cache-volume:/src/bf2sclone/cache - db-volume:/var/lib/mysql entrypoint: - /bin/sh @@ -80,34 +76,12 @@ services: - | set -eu - echo "Granting ASP php write permissions" - chmod 666 /src/ASP/system/config/config.php - - chown -R 82:82 /src/ASP/system/database/backups - find /src/ASP/system/database/backups -type d -exec chmod 750 {} \; - find /src/ASP/system/database/backups -type f -exec chmod 640 {} \; - - chown -R 82:82 /src/ASP/system/logs - find /src/ASP/system/logs -type d -exec chmod 750 {} \; - find /src/ASP/system/logs -type f -exec chmod 640 {} \; - - mkdir -p /src/ASP/system/snapshots/processed - mkdir -p /src/ASP/system/snapshots/temp - chown -R 82:82 /src/ASP/system/snapshots - find /src/ASP/system/snapshots -type d -exec chmod 750 {} \; - find /src/ASP/system/snapshots -type f -exec chmod 640 {} \; - - echo "Granting bf2sclone php write permissions" - chown -R 82:82 /src/bf2sclone/cache - find /src/bf2sclone/cache -type d -exec chmod 750 {} \; - find /src/bf2sclone/cache -type f -exec chmod 640 {} \; - - echo "Granting db's 'mysql' user write permissions" + echo "Granting db write permissions" chown -R 999:999 /var/lib/mysql # The gamespy ASP. The dashboard is available at https://asp.example.com/ASP - asp-nginx: - image: startersclan/bf2stats:2.5.1-asp-nginx + asp: + image: startersclan/bf2stats:2.5.1-asp labels: - "traefik.enable=true" - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" @@ -116,95 +90,84 @@ services: - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.entrypoints=web" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.rule=Host(`bf2web.gamespy.com`)" # Note: `bf2web.gamespy.com` doesn't need https. The BF2 client BFHQ, and the BF2 server python files, make a HTTP requests to `bf2web.gamespy.com` with `Host: bf2web.gamespy.com`. # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.rule=Host(`asp.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.rule=Host(`asp.example.com`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme" # Redirect http to https + - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.rule=Host(`asp.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - traefik-network: - bf2-network: - aliases: - - asp.example.com - - bf2web.gamespy.com # Important! Spoof Gamespy DNS for the BF2 server to reach our ASP server IP - - gamestats.gamespy.com # Spoof Gamespy DNS for the BF2 server to reach our ASP server IP. Doesn't seem to be used by the BF2 server, but spoof anyway. - - eapusher.dice.se # Spoof Gamespy DNS for the BF2 server to reach our ASP server IP. Doesn't seem to be used by the BF2 server, but spoof anyway. - depends_on: - - init-container - - asp-php - restart: unless-stopped - - asp-php: - image: startersclan/bf2stats:2.5.1-asp-php + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.entrypoints=websecure" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.tls=" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.rule=Host(`asp.example.com`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp.loadbalancer.server.port=80" + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=admin + - DB_PASS=admin volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize only if needed - # - ./config/ASP/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/ASP/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - config-volume:/src/ASP/system/config # For a stateful config file - logs-volume:/src/ASP/system/logs - snapshots-volume:/src/ASP/system/snapshots + # ports: + # - 8081:80 networks: - - bf2-network - depends_on: - - init-container + traefik-network: + bf2-network: + aliases: + - asp.example.com # For the ASP System Tests to resolve to itself + - bf2web.gamespy.com # Spoof gamespy DNS for the BF2 server connected to this network restart: unless-stopped # The bf2sclone for viewing BFHQ on the web. It is available at https://bf2sclone.example.com - bf2sclone-nginx: - image: startersclan/bf2stats:2.5.1-bf2sclone-nginx + bf2sclone: + image: startersclan/bf2stats:2.5.1-bf2sclone labels: - "traefik.enable=true" - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" # traefik v2 # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.rule=Host(`bf2sclone.example.com`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.middlewares=${COMPOSE_PROJECT_NAME?err}-bf2sclone-http-myRedirectScheme" # Redirect http to https + - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/bf2sclone/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - - traefik-network - - bf2-network - depends_on: - - init-container - - bf2sclone-php - restart: unless-stopped - - bf2sclone-php: - image: startersclan/bf2stats:2.5.1-bf2sclone-php + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.entrypoints=websecure" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.tls=" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.rule=Host(`bf2sclone.example.com`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-bf2sclone.loadbalancer.server.port=80" + environment: + # See ./src/bf2sclone/config.inc.php for all supported env vars + - DBIP=db + - DBNAME=bf2stats + - DBLOGIN=admin + - DBPASSWORD=admin + # - TITLE=BF2S Clone + - RANKING_REFRESH_TIME=0 + # - RANKING_HIDE_BOTS=false + # - RANKING_HIDE_HIDDEN_PLAYERS=false + # - LEADERBOARD_COUNT=25 volumes: - - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php:ro # Main config file. Customize as needed - # - ./config/bf2sclone/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/bf2sclone/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - bf2sclone-cache-volume:/src/bf2sclone/cache + # ports: + # - 8082:80 networks: + - traefik-network - bf2-network - depends_on: - - init-container restart: unless-stopped # The DB container db: image: mariadb:10.8 environment: - - MARIADB_ROOT_PASSWORD=admin # Change this to a strong password. + - MARIADB_ROOT_PASSWORD=admin - MARIADB_USER=admin - - MARIADB_PASSWORD=admin # Change this to a strong password + - MARIADB_PASSWORD=admin - MARIADB_DATABASE=bf2stats volumes: - - ./config/db/my.cnf:/etc/my.cnf:ro # Customize as needed + - ./config/db/my.cnf:/etc/my.cnf:ro # Config file. Customize as needed - db-volume:/var/lib/mysql networks: - bf2-network @@ -212,7 +175,7 @@ services: - init-container restart: unless-stopped - # The phpmyadmin interface for administrating the DB. It is available at phpmyadmin.example.com + # The phpmyadmin interface for administrating the DB. It is available at https://phpmyadmin.example.com phpmyadmin: image: phpmyadmin:5.2 labels: @@ -226,12 +189,14 @@ services: - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-phpmyadmin-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls=" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.rule=Host(`phpmyadmin.example.com`)" - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.loadbalancer.server.port=80" environment: - PMA_ABSOLUTE_URI=https://phpmyadmin.example.com # Enable this if behind a reverse proxy - PMA_HOST=db + # ports: + # - 8083:80 networks: - traefik-network - bf2-network @@ -248,6 +213,7 @@ volumes: prmasterserver-volume: traefik-acme-volume: backups-volume: + config-volume: logs-volume: snapshots-volume: bf2sclone-cache-volume: diff --git a/docs/full-bf2-stack-example/README.md b/docs/full-bf2-stack-example/README.md index 473df748..e4d45164 100644 --- a/docs/full-bf2-stack-example/README.md +++ b/docs/full-bf2-stack-example/README.md @@ -47,18 +47,16 @@ You should see something like: ```sh $ docker-compose up -[+] Running 10/0 - ⠿ Container bf2stats-prmasterserver-1 Running 0.0s - ⠿ Container bf2stats-phpmyadmin-1 Running 0.0s - ⠿ Container bf2stats-bf2-1 Running 0.0s - ⠿ Container bf2stats-traefik-1 Running 0.0s - ⠿ Container bf2stats-init-container-1 Created 0.0s - ⠿ Container bf2stats-db-1 Running 0.0s - ⠿ Container bf2stats-asp-php-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-php-1 Running 0.0s - ⠿ Container bf2stats-asp-nginx-1 Running 0.0s - ⠿ Container bf2stats-bf2sclone-nginx-1 Running 0.0s -Attaching to bf2stats-asp-nginx-1, bf2stats-asp-php-1, bf2stats-bf2-1, bf2stats-bf2sclone-nginx-1, bf2stats-bf2sclone-php-1, bf2stats-coredns-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-prmasterserver-1, bf2stats-traefik-1 + ✔ Container bf2stats-bf2sclone-1 Running 0.1s + ✔ Container bf2stats-init-container-1 Running 0.1s + ✔ Container bf2stats-asp-1 Running 0.1s + ✔ Container bf2stats-phpmyadmin-1 Running 0.1s + ✔ Container bf2stats-traefik-1 Running 0.1s + ✔ Container bf2stats-prmasterserver-1 Running 0.0s + ✔ Container bf2stats-coredns-1 Running 0.1s + ✔ Container bf2stats-db-1 Running 0.0s + ✔ Container bf2stats-bf2-1 Running 0.0s +Attaching to bf2stats-asp-1, bf2stats-bf2-1, bf2stats-bf2sclone-1, bf2stats-coredns-1, bf2stats-db-1, bf2stats-init-container-1, bf2stats-phpmyadmin-1, bf2stats-prmasterserver-1, bf2stats-traefik-1 ``` The full stack is now running: @@ -92,17 +90,17 @@ docker-compose restart bf2 Configure `coredns` to spoof all gamespy DNS in [config/coredns/hosts](config/coredns/hosts), replacing the IP addresses with your machine's external IP address which you specified in Step `2.`. Assuming your external IP is `192.168.1.100`, it should look like: ```txt -192.168.1.100 eapusher.dice.se 192.168.1.100 battlefield2.available.gamespy.com 192.168.1.100 battlefield2.master.gamespy.com 192.168.1.100 battlefield2.ms14.gamespy.com -192.168.1.100 gamestats.gamespy.com 192.168.1.100 master.gamespy.com 192.168.1.100 motd.gamespy.com 192.168.1.100 gpsp.gamespy.com 192.168.1.100 gpcm.gamespy.com 192.168.1.100 gamespy.com 192.168.1.100 bf2web.gamespy.com +192.168.1.100 gamestats.gamespy.com +192.168.1.100 eapusher.dice.se ``` Save the file. `coredns` immediately reads the changed file and serves the updated DNS records. @@ -183,21 +181,21 @@ docker-compose restart bf2 docker attach $( docker-compose ps -q bf2 ) # BF2 server - Exec into container docker exec -it $( docker-compose ps -q bf2) bash -# BF2 server - Read python logs +# BF2 server - Read logs docker exec -it $( docker-compose ps -q bf2 ) bash -c 'cat python/bf2/logs/bf2game_*' # BF2 server - List snapshots -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/sent' -docker exec -it $( docker-compose ps -q bf2 ) bash -c 'ls -al python/bf2/logs/snapshots/unsent' - -# asp-php - Exec into container -docker exec -it $( docker-compose ps -q asp-php ) sh -# asp-php - Read logs -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/stats_debug.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_awards.log -docker exec -it $( docker-compose ps -q asp-php ) cat /src/ASP/system/logs/validate_ranks.log -# asp-php - List snapshots -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/processed -docker exec -it $( docker-compose ps -q asp-php ) ls -al /src/ASP/system/snapshots/temp +docker exec -it $( docker-compose ps -q bf2 ) ls -alR python/bf2/logs/snapshots/unsent + +# asp - Exec into container +docker exec -it $( docker-compose ps -q asp ) sh +# asp - List backups +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/database/backups +# asp - List config +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/config +# asp - Read logs +docker exec -it $( docker-compose ps -q asp ) ls -al /src/ASP/system/logs +# asp - List snapshots +docker exec -it $( docker-compose ps -q asp ) ls -alR /src/ASP/system/snapshots # Dump the DB docker exec $( docker-compose ps -q db ) mysqldump -uroot -padmin bf2stats | gzip > bf2stats.sql.gz @@ -209,7 +207,7 @@ zcat bf2stats.sql.gz | docker exec -i $( docker-compose ps -q db ) mysql -uroot docker-compose down # Cleanup. Warning: This destroys the all data! -docker-compose down +docker-compose down --remove-orphans docker volume rm bf2stats_prmasterserver-volume docker volume rm bf2stats_traefik-acme-volume docker volume rm bf2stats_backups-volume @@ -221,7 +219,7 @@ docker volume rm bf2stats_db-volume ## Background: Keeping Battlefield 2 working -Problem: The Battlefield 2 client and server binaries are hardcoded with gamespy DNS records, e.g. `bf2web.gamespy.com`. Because gamespy has shut down, the DNS records no longer exist on public DNS servers. In order to keep the game's multiplayer working, we need: +Problem: The Battlefield 2 client and server binaries are hardcoded with gamespy DNS records, e.g. `bf2web.gamespy.com`. Because gamespy has shut down, the DNS records no longer exist on public DNS servers (read more about it [here](https://github.com/startersclan/docker-bf2/master/docs/usage.md#dns-spoofing)). In order to keep the game's multiplayer working, we need: - A gamespy replacement - solved by `PRMasterServer` - DNS resolution for gamespy DNS records - solved by either by: `1.` hex patching the game binaries; `2.` spoofing DNS server responses; `3.` spoofing DNS records via `hosts` file diff --git a/docs/full-bf2-stack-example/config/ASP/config.php b/docs/full-bf2-stack-example/config/ASP/config.php deleted file mode 100644 index 01422fe1..00000000 --- a/docs/full-bf2-stack-example/config/ASP/config.php +++ /dev/null @@ -1,40 +0,0 @@ - diff --git a/docs/full-bf2-stack-example/config/ASP/nginx/nginx.conf b/docs/full-bf2-stack-example/config/ASP/nginx/nginx.conf deleted file mode 100644 index d615c4c9..00000000 --- a/docs/full-bf2-stack-example/config/ASP/nginx/nginx.conf +++ /dev/null @@ -1,127 +0,0 @@ -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - - server { - listen 80; - # Ensure our redirects don't go to other ports, see https://serverfault.com/questions/351212/nginx-redirects-to-port-8080-when-accessing-url-without-slash - port_in_redirect off; - # Ensure our redirects are scheme-agnostic. Important behind a SSL-terminated load balancer. - absolute_redirect off; - - root /src; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - index index.php index.html index.htm; - - # Increase upload max body size - client_max_body_size 5m; - client_body_buffer_size 5m; - - # Restore IP from Proxy - set_real_ip_from 127.0.0.0/8; - set_real_ip_from 10.0.0.0/8; - set_real_ip_from 172.16.0.0/12; - set_real_ip_from 192.168.0.0/16; - real_ip_header X-Real-IP; - - # We don't want to pass calls to css, script, and image files to the index, - # whether they exist or not. So quit right here, and allow direct access - # to common format files. Add formats here to allow direct link access - location ~ \.(gif|png|jpe?g|bmp|css|js|swf|wav|avi|mpg|ttf|woff|ico)$ { - # Show empty flag - location ~ (/ASP/frontend/images/flags)/.*\.(png|jpeg|jpg|gif)$ { - try_files $uri $1/xx.png =404; - } - - access_log off; - add_header Cache-Control "public, s-maxage=600, maxage=600"; - try_files $uri =404; - } - - # Deny access to hidden files - location ~ /\.[^/]+$ { - return 401; - } - # Deny access to the frontend and system folders. All defined - # file extensions from the previous rewrite rule wont make it here, which allows - # direct access to images and such in these folders still. - location ~ ^/ASP/(frontend|system) { - return 401; - } - - # Pass .aspx to php - location ~ \.aspx$ { - add_header Cache-Control "public, s-maxage=0, maxage=0"; - - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Turn off chunked transfer encoding in HTTP/1.1. Older BF2 client or server python files may not be able to handle it - chunked_transfer_encoding off; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 10s; - fastcgi_split_path_info ^(.+\.aspx)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.aspx; - fastcgi_pass asp-php:9000; - } - - location ~ \.php$ { - # Check that the PHP script exists before passing it - try_files $fastcgi_script_name =404; - - # Disable fastcgi output buffering - fastcgi_buffering off; - - # Set fastcgi max execution response time - fastcgi_read_timeout 3600s; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_index index.php; - fastcgi_pass asp-php:9000; - } - - location / { - limit_except GET POST { - deny all; - } - - # Pass everything else to php - try_files $uri $uri/ =404; - } - } -} diff --git a/docs/full-bf2-stack-example/config/ASP/php-fpm.d/www.conf b/docs/full-bf2-stack-example/config/ASP/php-fpm.d/www.conf deleted file mode 100644 index eefbe39b..00000000 --- a/docs/full-bf2-stack-example/config/ASP/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php .aspx -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/docs/full-bf2-stack-example/config/ASP/php/conf.d/php.ini b/docs/full-bf2-stack-example/config/ASP/php/conf.d/php.ini deleted file mode 100644 index a79c6f23..00000000 --- a/docs/full-bf2-stack-example/config/ASP/php/conf.d/php.ini +++ /dev/null @@ -1,27 +0,0 @@ -[hardening] -disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file -cgi.fix_pathinfo = 0 -cgi.force_redirect = 1 -allow_url_fopen = 0 -allow_url_include = 0 -expose_php = 0 - -open_basedir = /src:/tmp -upload_tmp_dir = /tmp - -display_errors = 0 -log_errors = 1 -error_reporting = E_ALL -ignore_repeated_errors = 1 -#error_log = /var/lib/php/logs/error.log - -max_execution_time = 35 -max_input_time = 35 -file_uploads = 1 -post_max_size = 5M -upload_max_filesize = 5M - -[opcache] -opcache.enable=1 -opcache.memory_consumption = 64 -opcache.fast_shutdown = 0 diff --git a/docs/full-bf2-stack-example/config/bf2/mods/bf2/settings/serversettings-custom.con b/docs/full-bf2-stack-example/config/bf2/mods/bf2/settings/serversettings-custom.con index 386e277b..93bb7180 100644 --- a/docs/full-bf2-stack-example/config/bf2/mods/bf2/settings/serversettings-custom.con +++ b/docs/full-bf2-stack-example/config/bf2/mods/bf2/settings/serversettings-custom.con @@ -30,7 +30,7 @@ sv.tkNumPunishToKick 3 sv.tkPunishByDefault 0 sv.votingEnabled 1 sv.voteTime 90 -sv.minPlayersForVoting 2 +sv.minPlayersForVoting 1 sv.teamVoteOnly 1 sv.gameSpyPort 29900 sv.allowNATNegotiation 0 diff --git a/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py b/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py index 302e8c52..98171eb6 100644 --- a/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py +++ b/docs/full-bf2-stack-example/config/bf2/python/bf2/BF2StatisticsConfig-custom.py @@ -16,7 +16,7 @@ # ------------------------------------------------------------------------------ # Backend Web Server # ------------------------------------------------------------------------------ -http_backend_addr = 'asp-nginx' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. +http_backend_addr = 'asp' # Reach ASP over the `bf2-network` docker network. If your ASP is on another host, use its hostname or domain name here. http_backend_port = 80 http_backend_asp = '/ASP/bf2statistics.php' diff --git a/docs/full-bf2-stack-example/config/bf2sclone/config.inc.php b/docs/full-bf2-stack-example/config/bf2sclone/config.inc.php deleted file mode 100644 index 04226f2e..00000000 --- a/docs/full-bf2-stack-example/config/bf2sclone/config.inc.php +++ /dev/null @@ -1,23 +0,0 @@ - default: 600 seconds (10 minutes) - -// Whether to hide bots from rankings -define ('RANKING_HIDE_BOTS', false); - -// Whether to hide hidden players from rankings -define ('RANKING_HIDE_HIDDEN_PLAYERS', false); - -// Number of players to show on the leaderboard frontpage -define ('LEADERBOARD_COUNT', 25); -?> diff --git a/docs/full-bf2-stack-example/config/bf2sclone/php-fpm.d/www.conf b/docs/full-bf2-stack-example/config/bf2sclone/php-fpm.d/www.conf deleted file mode 100644 index b931b2cf..00000000 --- a/docs/full-bf2-stack-example/config/bf2sclone/php-fpm.d/www.conf +++ /dev/null @@ -1,10 +0,0 @@ -[www] -user = www-data -group = www-data -security.limit_extensions = .php -pm = dynamic -pm.max_children = 5 -pm.start_servers = 2 -pm.min_spare_servers = 1 -pm.max_spare_servers = 3 -pm.status_path = /status.php diff --git a/docs/full-bf2-stack-example/config/bf2sclone/php/conf.d/php.ini b/docs/full-bf2-stack-example/config/bf2sclone/php/conf.d/php.ini deleted file mode 100644 index a79c6f23..00000000 --- a/docs/full-bf2-stack-example/config/bf2sclone/php/conf.d/php.ini +++ /dev/null @@ -1,27 +0,0 @@ -[hardening] -disable_functions = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file -cgi.fix_pathinfo = 0 -cgi.force_redirect = 1 -allow_url_fopen = 0 -allow_url_include = 0 -expose_php = 0 - -open_basedir = /src:/tmp -upload_tmp_dir = /tmp - -display_errors = 0 -log_errors = 1 -error_reporting = E_ALL -ignore_repeated_errors = 1 -#error_log = /var/lib/php/logs/error.log - -max_execution_time = 35 -max_input_time = 35 -file_uploads = 1 -post_max_size = 5M -upload_max_filesize = 5M - -[opcache] -opcache.enable=1 -opcache.memory_consumption = 64 -opcache.fast_shutdown = 0 diff --git a/docs/full-bf2-stack-example/docker-compose.build.yml b/docs/full-bf2-stack-example/docker-compose.build.yml new file mode 100644 index 00000000..9b6e5700 --- /dev/null +++ b/docs/full-bf2-stack-example/docker-compose.build.yml @@ -0,0 +1,21 @@ +# This is a docker compose override file, for production builds with caching for CI environments +services: + asp: + build: + dockerfile: Dockerfile.asp + context: ../../ + target: prod + cache_from: + - type=local,src=/tmp/.buildx-cache-asp + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-asp,mode=max + + bf2sclone: + build: + dockerfile: Dockerfile.bf2sclone + context: ../../ + target: prod + cache_from: + - type=local,src=/tmp/.buildx-cache-bf2sclone + # cache_to: + # - type=local,dest=/tmp/.buildx-cache-bf2sclone,mode=max diff --git a/docs/full-bf2-stack-example/docker-compose.yml b/docs/full-bf2-stack-example/docker-compose.yml index e98b8f86..89868279 100644 --- a/docs/full-bf2-stack-example/docker-compose.yml +++ b/docs/full-bf2-stack-example/docker-compose.yml @@ -15,8 +15,7 @@ services: - gamespy-network - bf2-network depends_on: - - asp-nginx - - asp-php + - asp restart: unless-stopped tty: true stdin_open: true @@ -44,9 +43,6 @@ services: - gpsp.gamespy.com - gpcm.gamespy.com - gamespy.com - - bf2web.gamespy.com - - gamestats.gamespy.com - - eapusher.dice.se restart: unless-stopped # A DNS server to spoof gamespy's DNS records for BF2 clients or servers @@ -72,6 +68,8 @@ services: volumes: - ./config/coredns/Corefile:/Corefile:ro - ./config/coredns/hosts:/hosts:ro + networks: + - bf2-network restart: unless-stopped entrypoint: - /coredns @@ -90,6 +88,7 @@ services: ports: - 80:80 - 443:443 + # - 8080:8080 # Uncomment to view traefik dashboard on port 8080 networks: - traefik-public-network - traefik-network @@ -97,6 +96,7 @@ services: command: - --global.checknewversion=false - --global.sendanonymoususage=false + # - --api.insecure # Uncomment to view traefik dashboard on port 8080 # - --log.level=DEBUG - --providers.docker=true - --providers.docker.exposedbydefault=false @@ -108,15 +108,10 @@ services: - --certificatesresolvers.myresolver.acme.email=postmaster@example.com - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json - # The init container that sets up permissions for the asp and db volumes + # The init container that sets up permissions init-container: image: alpine:latest volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php - - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. - - logs-volume:/src/ASP/system/logs - - snapshots-volume:/src/ASP/system/snapshots - - bf2sclone-cache-volume:/src/bf2sclone/cache - db-volume:/var/lib/mysql entrypoint: - /bin/sh @@ -125,34 +120,12 @@ services: - | set -eu - echo "Granting ASP php write permissions" - chmod 666 /src/ASP/system/config/config.php - - chown -R 82:82 /src/ASP/system/database/backups - find /src/ASP/system/database/backups -type d -exec chmod 750 {} \; - find /src/ASP/system/database/backups -type f -exec chmod 640 {} \; - - chown -R 82:82 /src/ASP/system/logs - find /src/ASP/system/logs -type d -exec chmod 750 {} \; - find /src/ASP/system/logs -type f -exec chmod 640 {} \; - - mkdir -p /src/ASP/system/snapshots/processed - mkdir -p /src/ASP/system/snapshots/temp - chown -R 82:82 /src/ASP/system/snapshots - find /src/ASP/system/snapshots -type d -exec chmod 750 {} \; - find /src/ASP/system/snapshots -type f -exec chmod 640 {} \; - - echo "Granting bf2sclone php write permissions" - chown -R 82:82 /src/bf2sclone/cache - find /src/bf2sclone/cache -type d -exec chmod 750 {} \; - find /src/bf2sclone/cache -type f -exec chmod 640 {} \; - - echo "Granting db's 'mysql' user write permissions" + echo "Granting db write permissions" chown -R 999:999 /var/lib/mysql # The gamespy ASP. The dashboard is available at https://asp.example.com/ASP - asp-nginx: - image: startersclan/bf2stats:2.5.1-asp-nginx + asp: + image: startersclan/bf2stats:2.5.1-asp labels: - "traefik.enable=true" - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" @@ -161,92 +134,84 @@ services: - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.entrypoints=web" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-gamespy-http.rule=Host(`bf2web.gamespy.com`)" # Note: `bf2web.gamespy.com` doesn't need https. The BF2 client BFHQ, and the BF2 server python files, make a HTTP requests to `bf2web.gamespy.com` with `Host: bf2web.gamespy.com`. # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.rule=Host(`asp.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.rule=Host(`asp.example.com`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-http.middlewares=${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme" # Redirect http to https + - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-asp-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp-nginx.rule=Host(`asp.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - traefik-network: - bf2-network: - aliases: - - asp.example.com - depends_on: - - init-container - - asp-php - restart: unless-stopped - - asp-php: - image: startersclan/bf2stats:2.5.1-asp-php + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.entrypoints=websecure" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.tls=" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-asp.rule=Host(`asp.example.com`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-asp.loadbalancer.server.port=80" + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=admin + - DB_PASS=admin volumes: - - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize only if needed - # - ./config/ASP/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/ASP/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - config-volume:/src/ASP/system/config # For a stateful config file - logs-volume:/src/ASP/system/logs - snapshots-volume:/src/ASP/system/snapshots + # ports: + # - 8081:80 networks: - - bf2-network - depends_on: - - init-container + traefik-network: + bf2-network: + aliases: + - asp.example.com # For the ASP System Tests to resolve to itself + - bf2web.gamespy.com # Spoof gamespy DNS for the BF2 server connected to this network restart: unless-stopped # The bf2sclone for viewing BFHQ on the web. It is available at https://bf2sclone.example.com - bf2sclone-nginx: - image: startersclan/bf2stats:2.5.1-bf2sclone-nginx + bf2sclone: + image: startersclan/bf2stats:2.5.1-bf2sclone labels: - "traefik.enable=true" - "traefik.docker.network=${COMPOSE_PROJECT_NAME?err}_traefik-network" # traefik v2 # http - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.entrypoints=web" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http.middlewares=${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme" # Redirect http to https - - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.entrypoints=web" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.rule=Host(`bf2sclone.example.com`)" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http.middlewares=${COMPOSE_PROJECT_NAME?err}-bf2sclone-http-myRedirectScheme" # Redirect http to https + - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-bf2sclone-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.tls" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.rule=Host(`bf2sclone.example.com`)" - - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-bf2sclone-nginx.loadbalancer.server.port=80" - # volumes: - # - ./config/bf2sclone/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # Customize only if needed - networks: - - traefik-network - - bf2-network - depends_on: - - init-container - - bf2sclone-php - restart: unless-stopped - - bf2sclone-php: - image: startersclan/bf2stats:2.5.1-bf2sclone-php + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.entrypoints=websecure" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.tls=" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-bf2sclone.rule=Host(`bf2sclone.example.com`)" + - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-bf2sclone.loadbalancer.server.port=80" + environment: + # See ./src/bf2sclone/config.inc.php for all supported env vars + - DBIP=db + - DBNAME=bf2stats + - DBLOGIN=admin + - DBPASSWORD=admin + # - TITLE=BF2S Clone + - RANKING_REFRESH_TIME=0 + # - RANKING_HIDE_BOTS=false + # - RANKING_HIDE_HIDDEN_PLAYERS=false + # - LEADERBOARD_COUNT=25 volumes: - - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php:ro # Main config file. Customize as needed - # - ./config/bf2sclone/php/conf.d/php.ini:/usr/local/etc/php/conf.d/php.ini:ro # Customize only if needed - # - ./config/bf2sclone/php-fpm.d/www.conf:/usr/local/etc/php-fpm.d/www.conf:ro # Customize only if needed - bf2sclone-cache-volume:/src/bf2sclone/cache + # ports: + # - 8082:80 networks: + - traefik-network - bf2-network - depends_on: - - init-container restart: unless-stopped # The DB container db: image: mariadb:10.8 environment: - - MARIADB_ROOT_PASSWORD=admin # Change this to a strong password. + - MARIADB_ROOT_PASSWORD=admin - MARIADB_USER=admin - - MARIADB_PASSWORD=admin # Change this to a strong password + - MARIADB_PASSWORD=admin - MARIADB_DATABASE=bf2stats volumes: - - ./config/db/my.cnf:/etc/my.cnf:ro # Customize as needed + - ./config/db/my.cnf:/etc/my.cnf:ro # Config file. Customize as needed - db-volume:/var/lib/mysql networks: - bf2-network @@ -254,7 +219,7 @@ services: - init-container restart: unless-stopped - # The phpmyadmin interface for administrating the DB. It is available at phpmyadmin.example.com + # The phpmyadmin interface for administrating the DB. It is available at https://phpmyadmin.example.com phpmyadmin: image: phpmyadmin:5.2 labels: @@ -268,12 +233,14 @@ services: - "traefik.http.middlewares.${COMPOSE_PROJECT_NAME?err}-phpmyadmin-http-myRedirectScheme.redirectScheme.scheme=https" # Redirect http to https # https - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.entrypoints=websecure" - - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls" + - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.tls=" - "traefik.http.routers.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.rule=Host(`phpmyadmin.example.com`)" - "traefik.http.services.${COMPOSE_PROJECT_NAME?err}-phpmyadmin.loadbalancer.server.port=80" environment: - PMA_ABSOLUTE_URI=https://phpmyadmin.example.com # Enable this if behind a reverse proxy - PMA_HOST=db + # ports: + # - 8083:80 networks: - traefik-network - bf2-network @@ -290,6 +257,7 @@ volumes: prmasterserver-volume: traefik-acme-volume: backups-volume: + config-volume: logs-volume: snapshots-volume: bf2sclone-cache-volume: diff --git a/docs/upgrading-docker-images-to-2.6.md b/docs/upgrading-docker-images-to-2.6.md new file mode 100644 index 00000000..42f69e85 --- /dev/null +++ b/docs/upgrading-docker-images-to-2.6.md @@ -0,0 +1,144 @@ +# Upgrade docker images to v2.6.x + +In <= v2.5.x, `asp` and `bf2sclone` each had separate `nginx` and `php` images. + +Since v2.6.0: `asp` and `bf2sclone` each contains both `nginx` and `php`, with environment variable support, and entrypoint that sets the correct permissions. + +Benefits: + +- Easier to deploy / upgrade. No need to separate `nginx` and `php` containers +- Environment variable configuration means no more need to mount config into `asp` and `bf2sclone` containers +- Entrypoint script sets permissions on volumes. `init-container` should only need to set permissions for `db` volume + +## Upgrade steps + +These steps are demonstrated using Docker Compose. + +1. Merge the networks and volumes of `asp-nginx` and `asp-php` into a single `asp` container, switch to a volume and env vars for `asp` configuration, and remove `depends_on`. + +For instance, from this: + +```yaml + asp-nginx: + image: startersclan/bf2stats:2.5.1-asp-nginx + volumes: + - ./config/ASP/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + networks: + traefik-network: + bf2-network: + aliases: + - asp.example.com # For the ASP System Tests to resolve to itself + - bf2web.gamespy.com # Spoof gamespy DNS for the BF2 server connected to this network + depends_on: + - init-container + - asp-php + + asp-php: + image: startersclan/bf2stats:2.5.1-asp-php + volumes: + - ./config/ASP/config.php:/src/ASP/system/config/config.php # Main config file. Must be writeable or else ASP will throw an exception. Customize only if needed + - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - logs-volume:/src/ASP/system/logs + - snapshots-volume:/src/ASP/system/snapshots + networks: + - traefik-network + - bf2-network + depends_on: + - init-container +``` + +To this: + +```yaml + asp: + image: startersclan/bf2stats:2.6.0-asp + environment: + # See ./src/ASP/system/config/config.php for all supported env vars + - DB_HOST=db + - DB_PORT=3306 + - DB_NAME=bf2stats + - DB_USER=admin + - DB_PASS=admin + volumes: + - backups-volume:/src/ASP/system/database/backups # This volume is effectively unused since ASP doesn't allow DB backups for a remote DB, but mount it anyway to avoid errors. + - config-volume:/src/ASP/system/config # For a stateful config file + - logs-volume:/src/ASP/system/logs + - snapshots-volume:/src/ASP/system/snapshots + networks: + traefik-network: + bf2-network: + aliases: + - asp.example.com # For the ASP System Tests to resolve to itself + - bf2web.gamespy.com # Spoof gamespy DNS for the BF2 server connected to this network + +volumes: + config-volume: +``` + +2. Merge the networks and volumes of `bf2sclone-nginx` and `bf2sclone-php` into a single `bf2sclone` container, switch to env vars for `bf2sclone` configuration, and remove `depends_on`. + +For instance, from this: + +```yaml + bf2sclone-nginx: + image: startersclan/bf2stats:2.5.1-bf2sclone-nginx + depends_on: + - init-container + - bf2sclone-php + networks: + - traefik-network + - bf2-network + + bf2sclone-php: + image: startersclan/bf2stats:2.5.1-bf2sclone-php + volumes: + - ./config/bf2sclone/config.inc.php:/src/bf2sclone/config.inc.php:ro # Main config file. Customize as needed + - bf2sclone-cache-volume:/src/bf2sclone/cache + networks: + - bf2-network + depends_on: + - init-container +``` + +To this: + +```yaml + bf2sclone: + image: startersclan/bf2stats:2.6.0-bf2sclone + environment: + # See ./src/bf2sclone/config.inc.php for all supported env vars + - DBIP=db + - DBNAME=bf2stats + - DBLOGIN=admin + - DBPASSWORD=admin + # - TITLE=BF2S Clone + # - RANKING_REFRESH_TIME=600 + # - RANKING_HIDE_BOTS=false + # - RANKING_HIDE_HIDDEN_PLAYERS=false + # - LEADERBOARD_COUNT=25 + volumes: + - bf2sclone-cache-volume:/src/bf2sclone/cache + networks: + - traefik-network + - bf2-network +``` + +3. If you have `init-container`, now it only needs to set permission for the `db` volume: + +```yaml + init-container: + image: alpine:latest + volumes: + - db-volume:/var/lib/mysql + entrypoint: + - /bin/sh + command: + - -c + - | + set -eu + + echo "Granting db write permissions" + chown -R 999:999 /var/lib/mysql +``` + +Done. Enjoy the simpler setup 😀 diff --git a/src/bf2sclone/config.inc.php b/src/bf2sclone/config.inc.php index 04226f2e..c9733688 100644 --- a/src/bf2sclone/config.inc.php +++ b/src/bf2sclone/config.inc.php @@ -1,23 +1,35 @@ default: 600 seconds (10 minutes) +defineVar('RANKING_REFRESH_TIME', 600); // -> default: 600 seconds (10 minutes) // Whether to hide bots from rankings -define ('RANKING_HIDE_BOTS', false); +defineVar('RANKING_HIDE_BOTS', false); // Whether to hide hidden players from rankings -define ('RANKING_HIDE_HIDDEN_PLAYERS', false); +defineVar('RANKING_HIDE_HIDDEN_PLAYERS', false); // Number of players to show on the leaderboard frontpage -define ('LEADERBOARD_COUNT', 25); +defineVar('LEADERBOARD_COUNT', 25); ?> diff --git a/test/.env b/test/.env new file mode 100644 index 00000000..9a2f2c31 --- /dev/null +++ b/test/.env @@ -0,0 +1 @@ +COMPOSE_PROJECT_NAME=bf2stats diff --git a/test/docker-compose.yml b/test/docker-compose.yml new file mode 100644 index 00000000..7bbce4e3 --- /dev/null +++ b/test/docker-compose.yml @@ -0,0 +1,35 @@ +version: '2.2' +services: + test-container-networking: + image: alpine:latest + volumes: + - ./:/test:ro + networks: + - gamespy-network + - bf2-network + stop_signal: SIGKILL + working_dir: /test + entrypoint: + - /bin/sh + command: + - -c + - | + sleep infinity + + test-host-networking: + image: alpine:latest + volumes: + - ./:/test:ro + network_mode: host + stop_signal: SIGKILL + working_dir: /test + entrypoint: + - /bin/sh + command: + - -c + - | + sleep infinity + +networks: + bf2-network: + gamespy-network: diff --git a/test/snapshots/-dalian_plant_20231107_2013.txt b/test/snapshots/-dalian_plant_20231107_2013.txt new file mode 100644 index 00000000..bd3d5efa --- /dev/null +++ b/test/snapshots/-dalian_plant_20231107_2013.txt @@ -0,0 +1 @@ +\Default Server Name\gameport\16567\queryport\29900\mapname\dalian_plant\mapid\101\mapstart\1699387872.39\mapend\1699387990.61\win\1\gm\2\m\101\v\bf2\pc\64\rwa\2\ra1\2\rs1\96\ra2\0\rs2\85\rst2\85\pID_0\28999904\name_0\J. Andersson\t_0\1\a_0\2\ctime_0\88\c_0\1\ip_0\127.0.0.1\ai_0\1\rs_0\0\cs_0\0\ss_0\0\ts_0\0\kills_0\0\deaths_0\0\cpc_0\0\cpa_0\0\cpd_0\0\ka_0\0\he_0\0\rev_0\0\rsp_0\0\rep_0\0\tre_0\0\drs_0\0\tmkl_0\0\tmdg_0\0\tmvd_0\0\su_0\0\ks_0\0\ds_0\0\rank_0\0\ban_0\0\kck_0\0\tco_0\0\tsl_0\88\tsm_0\0\tlw_0\0\ta0_0\0\ta1_0\0\ta2_0\88\ta3_0\0\ta4_0\0\ta5_0\0\ta6_0\0\ta7_0\0\ta8_0\0\ta9_0\0\ta10_0\0\ta11_0\0\ta12_0\0\ta13_0\0\tv0_0\0\tv1_0\0\tv2_0\0\tv3_0\0\tv4_0\0\tv5_0\0\tv6_0\0\tvp_0\0\kv0_0\0\kv1_0\0\kv2_0\0\kv3_0\0\kv4_0\0\kv5_0\0\kv6_0\0\bv0_0\0\bv1_0\0\bv2_0\0\bv3_0\0\bv4_0\0\bv5_0\0\bv6_0\0\kvr0_0\0\kvr1_0\0\kvr2_0\0\kvr3_0\0\kvr4_0\0\kvr5_0\0\kvr6_0\0\tk0_0\0\tk1_0\0\tk2_0\0\tk3_0\0\tk4_0\78\tk5_0\0\tk6_0\0\kk0_0\0\kk1_0\0\kk2_0\0\kk3_0\0\kk4_0\0\kk5_0\0\kk6_0\0\dk0_0\0\dk1_0\0\dk2_0\0\dk3_0\0\dk4_0\0\dk5_0\0\dk6_0\0\tw0_0\0\tw1_0\0\tw2_0\74\tw3_0\0\tw4_0\0\tw5_0\4\tw6_0\0\tw7_0\0\tw8_0\0\te0_0\0\te1_0\0\te3_0\0\te2_0\0\te4_0\0\te5_0\0\te6_0\0\te7_0\0\te8_0\0\kw0_0\0\kw1_0\0\kw2_0\0\kw3_0\0\kw4_0\0\kw5_0\0\kw6_0\0\kw7_0\0\kw8_0\0\ke0_0\0\ke1_0\0\ke3_0\0\ke2_0\0\ke4_0\0\ke5_0\0\bw0_0\0\bw1_0\0\bw2_0\0\bw3_0\0\bw4_0\0\bw5_0\0\bw6_0\0\bw7_0\0\bw8_0\0\be0_0\0\be1_0\0\be3_0\0\be2_0\0\be4_0\0\be5_0\0\be8_0\0\be9_0\0\de6_0\0\de7_0\0\de8_0\0\sw0_0\0\sw1_0\0\sw2_0\30\sw3_0\0\sw4_0\0\sw5_0\15\sw6_0\0\sw7_0\0\sw8_0\0\se0_0\0\se1_0\0\se2_0\0\se3_0\0\se4_0\0\se5_0\0\hw0_0\0\hw1_0\0\hw2_0\1\hw3_0\0\hw4_0\0\hw5_0\1\hw6_0\0\hw7_0\0\hw8_0\0\he0_0\0\he1_0\0\he2_0\0\he3_0\0\he4_0\0\he5_0\0\pID_1\28999901\name_1\L. Castillo\t_1\1\a_1\2\ctime_1\88\c_1\1\ip_1\127.0.0.1\ai_1\1\rs_1\0\cs_1\0\ss_1\0\ts_1\0\kills_1\0\deaths_1\0\cpc_1\0\cpa_1\0\cpd_1\0\ka_1\0\he_1\0\rev_1\0\rsp_1\0\rep_1\0\tre_1\0\drs_1\0\tmkl_1\1\tmdg_1\0\tmvd_1\0\su_1\0\ks_1\0\ds_1\0\rank_1\0\ban_1\0\kck_1\0\tco_1\0\tsl_1\0\tsm_1\88\tlw_1\0\ta0_1\0\ta1_1\0\ta2_1\88\ta3_1\0\ta4_1\0\ta5_1\0\ta6_1\0\ta7_1\0\ta8_1\0\ta9_1\0\ta10_1\0\ta11_1\0\ta12_1\0\ta13_1\0\tv0_1\0\tv1_1\0\tv2_1\0\tv3_1\0\tv4_1\66\tv5_1\0\tv6_1\0\tvp_1\0\kv0_1\0\kv1_1\0\kv2_1\0\kv3_1\0\kv4_1\0\kv5_1\0\kv6_1\0\bv0_1\0\bv1_1\0\bv2_1\0\bv3_1\0\bv4_1\0\bv5_1\0\bv6_1\0\kvr0_1\0\kvr1_1\0\kvr2_1\0\kvr3_1\0\kvr4_1\0\kvr5_1\0\kvr6_1\0\tk0_1\0\tk1_1\0\tk2_1\0\tk3_1\88\tk4_1\0\tk5_1\0\tk6_1\0\kk0_1\0\kk1_1\0\kk2_1\0\kk3_1\0\kk4_1\0\kk5_1\0\kk6_1\0\dk0_1\0\dk1_1\0\dk2_1\0\dk3_1\0\dk4_1\0\dk5_1\0\dk6_1\0\tw0_1\21\tw1_1\0\tw2_1\0\tw3_1\0\tw4_1\0\tw5_1\0\tw6_1\0\tw7_1\66\tw8_1\0\te0_1\0\te1_1\0\te3_1\0\te2_1\0\te4_1\0\te5_1\0\te6_1\0\te7_1\0\te8_1\0\kw0_1\0\kw1_1\0\kw2_1\0\kw3_1\0\kw4_1\0\kw5_1\0\kw6_1\0\kw7_1\0\kw8_1\0\ke0_1\0\ke1_1\0\ke3_1\0\ke2_1\0\ke4_1\0\ke5_1\0\bw0_1\0\bw1_1\0\bw2_1\0\bw3_1\0\bw4_1\0\bw5_1\0\bw6_1\0\bw7_1\0\bw8_1\0\be0_1\0\be1_1\0\be3_1\0\be2_1\0\be4_1\0\be5_1\0\be8_1\0\be9_1\0\de6_1\0\de7_1\0\de8_1\0\sw0_1\0\sw1_1\0\sw2_1\0\sw3_1\0\sw4_1\0\sw5_1\0\sw6_1\0\sw7_1\47\sw8_1\0\se0_1\0\se1_1\0\se2_1\0\se3_1\0\se4_1\0\se5_1\0\hw0_1\0\hw1_1\0\hw2_1\0\hw3_1\0\hw4_1\0\hw5_1\0\hw6_1\0\hw7_1\0\hw8_1\0\he0_1\0\he1_1\0\he2_1\0\he3_1\0\he4_1\0\he5_1\0\pID_2\28999909\name_2\F. Morales\t_2\1\a_2\2\ctime_2\88\c_2\1\ip_2\127.0.0.1\ai_2\1\rs_2\1\cs_2\0\ss_2\0\ts_2\1\kills_2\0\deaths_2\0\cpc_2\0\cpa_2\0\cpd_2\0\ka_2\0\he_2\0\rev_2\0\rsp_2\0\rep_2\0\tre_2\0\drs_2\1\tmkl_2\0\tmdg_2\0\tmvd_2\0\su_2\0\ks_2\0\ds_2\0\rank_2\0\ban_2\0\kck_2\0\tco_2\0\tsl_2\0\tsm_2\88\tlw_2\0\ta0_2\0\ta1_2\0\ta2_2\88\ta3_2\0\ta4_2\0\ta5_2\0\ta6_2\0\ta7_2\0\ta8_2\0\ta9_2\0\ta10_2\0\ta11_2\0\ta12_2\0\ta13_2\0\tv0_2\0\tv1_2\0\tv2_2\2\tv3_2\0\tv4_2\0\tv5_2\0\tv6_2\0\tvp_2\0\kv0_2\0\kv1_2\0\kv2_2\0\kv3_2\0\kv4_2\0\kv5_2\0\kv6_2\0\bv0_2\0\bv1_2\0\bv2_2\0\bv3_2\0\bv4_2\0\bv5_2\0\bv6_2\0\kvr0_2\0\kvr1_2\0\kvr2_2\0\kvr3_2\0\kvr4_2\0\kvr5_2\0\kvr6_2\0\tk0_2\0\tk1_2\0\tk2_2\0\tk3_2\0\tk4_2\0\tk5_2\88\tk6_2\0\kk0_2\0\kk1_2\0\kk2_2\0\kk3_2\0\kk4_2\0\kk5_2\0\kk6_2\0\dk0_2\0\dk1_2\0\dk2_2\0\dk3_2\0\dk4_2\0\dk5_2\0\dk6_2\0\tw0_2\0\tw1_2\0\tw2_2\0\tw3_2\86\tw4_2\0\tw5_2\1\tw6_2\0\tw7_2\0\tw8_2\0\te0_2\0\te1_2\0\te3_2\1\te2_2\0\te4_2\0\te5_2\0\te6_2\0\te7_2\0\te8_2\0\kw0_2\0\kw1_2\0\kw2_2\0\kw3_2\0\kw4_2\0\kw5_2\0\kw6_2\0\kw7_2\0\kw8_2\0\ke0_2\0\ke1_2\0\ke3_2\0\ke2_2\0\ke4_2\0\ke5_2\0\bw0_2\0\bw1_2\0\bw2_2\0\bw3_2\0\bw4_2\0\bw5_2\0\bw6_2\0\bw7_2\0\bw8_2\0\be0_2\0\be1_2\0\be3_2\0\be2_2\0\be4_2\0\be5_2\0\be8_2\0\be9_2\0\de6_2\0\de7_2\0\de8_2\0\sw0_2\0\sw1_2\0\sw2_2\0\sw3_2\168\sw4_2\0\sw5_2\0\sw6_2\0\sw7_2\0\sw8_2\0\se0_2\0\se1_2\0\se2_2\0\se3_2\0\se4_2\0\se5_2\0\hw0_2\0\hw1_2\0\hw2_2\0\hw3_2\3\hw4_2\0\hw5_2\0\hw6_2\0\hw7_2\0\hw8_2\0\he0_2\0\he1_2\0\he2_2\0\he3_2\0\he4_2\0\he5_2\0\pID_3\28999982\name_3\M. Sjoberg\t_3\1\a_3\2\ctime_3\88\c_3\1\ip_3\127.0.0.1\ai_3\1\rs_3\2\cs_3\0\ss_3\2\ts_3\0\kills_3\1\deaths_3\0\cpc_3\0\cpa_3\0\cpd_3\0\ka_3\0\he_3\0\rev_3\0\rsp_3\0\rep_3\0\tre_3\0\drs_3\0\tmkl_3\0\tmdg_3\0\tmvd_3\0\su_3\0\ks_3\1\ds_3\0\rank_3\0\ban_3\0\kck_3\0\tco_3\0\tsl_3\0\tsm_3\88\tlw_3\0\ta0_3\0\ta1_3\0\ta2_3\88\ta3_3\0\ta4_3\0\ta5_3\0\ta6_3\0\ta7_3\0\ta8_3\0\ta9_3\0\ta10_3\0\ta11_3\0\ta12_3\0\ta13_3\0\mvns_3\28999994\mvks_3\1\tv0_3\0\tv1_3\0\tv2_3\11\tv3_3\0\tv4_3\0\tv5_3\0\tv6_3\0\tvp_3\0\kv0_3\0\kv1_3\0\kv2_3\1\kv3_3\0\kv4_3\0\kv5_3\0\kv6_3\0\bv0_3\0\bv1_3\0\bv2_3\0\bv3_3\0\bv4_3\0\bv5_3\0\bv6_3\0\kvr0_3\0\kvr1_3\0\kvr2_3\0\kvr3_3\0\kvr4_3\0\kvr5_3\0\kvr6_3\0\tk0_3\88\tk1_3\0\tk2_3\0\tk3_3\0\tk4_3\0\tk5_3\0\tk6_3\0\kk0_3\1\kk1_3\0\kk2_3\0\kk3_3\0\kk4_3\0\kk5_3\0\kk6_3\0\dk0_3\0\dk1_3\0\dk2_3\0\dk3_3\0\dk4_3\0\dk5_3\0\dk6_3\0\tw0_3\0\tw1_3\0\tw2_3\0\tw3_3\0\tw4_3\0\tw5_3\0\tw6_3\0\tw7_3\76\tw8_3\0\te0_3\0\te1_3\0\te3_3\0\te2_3\0\te4_3\0\te5_3\0\te6_3\0\te7_3\0\te8_3\0\kw0_3\0\kw1_3\0\kw2_3\0\kw3_3\0\kw4_3\0\kw5_3\0\kw6_3\0\kw7_3\0\kw8_3\0\ke0_3\0\ke1_3\0\ke3_3\0\ke2_3\0\ke4_3\0\ke5_3\0\bw0_3\0\bw1_3\0\bw2_3\0\bw3_3\0\bw4_3\0\bw5_3\0\bw6_3\0\bw7_3\0\bw8_3\0\be0_3\0\be1_3\0\be3_3\0\be2_3\0\be4_3\0\be5_3\0\be8_3\0\be9_3\0\de6_3\0\de7_3\0\de8_3\0\sw0_3\0\sw1_3\0\sw2_3\0\sw3_3\0\sw4_3\0\sw5_3\0\sw6_3\0\sw7_3\0\sw8_3\0\se0_3\0\se1_3\0\se2_3\0\se3_3\0\se4_3\0\se5_3\0\hw0_3\0\hw1_3\0\hw2_3\0\hw3_3\0\hw4_3\0\hw5_3\0\hw6_3\0\hw7_3\0\hw8_3\0\he0_3\0\he1_3\0\he2_3\0\he3_3\0\he4_3\0\he5_3\0\pID_4\28999913\name_4\T. Soderman\t_4\1\a_4\2\ctime_4\88\c_4\1\ip_4\127.0.0.1\ai_4\1\rs_4\0\cs_4\0\ss_4\0\ts_4\0\kills_4\0\deaths_4\0\cpc_4\0\cpa_4\0\cpd_4\0\ka_4\0\he_4\0\rev_4\0\rsp_4\0\rep_4\0\tre_4\0\drs_4\0\tmkl_4\0\tmdg_4\0\tmvd_4\0\su_4\0\ks_4\0\ds_4\0\rank_4\0\ban_4\0\kck_4\0\tco_4\0\tsl_4\88\tsm_4\0\tlw_4\0\ta0_4\0\ta1_4\0\ta2_4\88\ta3_4\0\ta4_4\0\ta5_4\0\ta6_4\0\ta7_4\0\ta8_4\0\ta9_4\0\ta10_4\0\ta11_4\0\ta12_4\0\ta13_4\0\tv0_4\0\tv1_4\0\tv2_4\0\tv3_4\0\tv4_4\0\tv5_4\0\tv6_4\0\tvp_4\0\kv0_4\0\kv1_4\0\kv2_4\0\kv3_4\0\kv4_4\0\kv5_4\0\kv6_4\0\bv0_4\0\bv1_4\0\bv2_4\0\bv3_4\0\bv4_4\0\bv5_4\0\bv6_4\0\kvr0_4\0\kvr1_4\0\kvr2_4\0\kvr3_4\0\kvr4_4\0\kvr5_4\0\kvr6_4\0\tk0_4\0\tk1_4\0\tk2_4\0\tk3_4\0\tk4_4\88\tk5_4\0\tk6_4\0\kk0_4\0\kk1_4\0\kk2_4\0\kk3_4\0\kk4_4\0\kk5_4\0\kk6_4\0\dk0_4\0\dk1_4\0\dk2_4\0\dk3_4\0\dk4_4\0\dk5_4\0\dk6_4\0\tw0_4\0\tw1_4\0\tw2_4\88\tw3_4\0\tw4_4\0\tw5_4\0\tw6_4\0\tw7_4\0\tw8_4\0\te0_4\0\te1_4\0\te3_4\0\te2_4\0\te4_4\0\te5_4\0\te6_4\0\te7_4\0\te8_4\0\kw0_4\0\kw1_4\0\kw2_4\0\kw3_4\0\kw4_4\0\kw5_4\0\kw6_4\0\kw7_4\0\kw8_4\0\ke0_4\0\ke1_4\0\ke3_4\0\ke2_4\0\ke4_4\0\ke5_4\0\bw0_4\0\bw1_4\0\bw2_4\0\bw3_4\0\bw4_4\0\bw5_4\0\bw6_4\0\bw7_4\0\bw8_4\0\be0_4\0\be1_4\0\be3_4\0\be2_4\0\be4_4\0\be5_4\0\be8_4\0\be9_4\0\de6_4\0\de7_4\0\de8_4\0\sw0_4\0\sw1_4\0\sw2_4\0\sw3_4\0\sw4_4\0\sw5_4\0\sw6_4\0\sw7_4\0\sw8_4\0\se0_4\0\se1_4\0\se2_4\0\se3_4\0\se4_4\0\se5_4\0\hw0_4\0\hw1_4\0\hw2_4\0\hw3_4\0\hw4_4\0\hw5_4\0\hw6_4\0\hw7_4\0\hw8_4\0\he0_4\0\he1_4\0\he2_4\0\he3_4\0\he4_4\0\he5_4\0\pID_5\28999970\name_5\R. Davey\t_5\1\a_5\2\ctime_5\88\c_5\1\ip_5\127.0.0.1\ai_5\1\rs_5\0\cs_5\0\ss_5\0\ts_5\0\kills_5\0\deaths_5\0\cpc_5\0\cpa_5\0\cpd_5\0\ka_5\0\he_5\0\rev_5\0\rsp_5\0\rep_5\0\tre_5\0\drs_5\0\tmkl_5\0\tmdg_5\0\tmvd_5\0\su_5\0\ks_5\0\ds_5\0\rank_5\0\ban_5\0\kck_5\0\tco_5\0\tsl_5\0\tsm_5\88\tlw_5\0\ta0_5\0\ta1_5\0\ta2_5\88\ta3_5\0\ta4_5\0\ta5_5\0\ta6_5\0\ta7_5\0\ta8_5\0\ta9_5\0\ta10_5\0\ta11_5\0\ta12_5\0\ta13_5\0\tv0_5\0\tv1_5\0\tv2_5\0\tv3_5\0\tv4_5\0\tv5_5\0\tv6_5\0\tvp_5\0\kv0_5\0\kv1_5\0\kv2_5\0\kv3_5\0\kv4_5\0\kv5_5\0\kv6_5\0\bv0_5\0\bv1_5\0\bv2_5\0\bv3_5\0\bv4_5\0\bv5_5\0\bv6_5\0\kvr0_5\0\kvr1_5\0\kvr2_5\0\kvr3_5\0\kvr4_5\0\kvr5_5\0\kvr6_5\0\tk0_5\0\tk1_5\0\tk2_5\0\tk3_5\88\tk4_5\0\tk5_5\0\tk6_5\0\kk0_5\0\kk1_5\0\kk2_5\0\kk3_5\0\kk4_5\0\kk5_5\0\kk6_5\0\dk0_5\0\dk1_5\0\dk2_5\0\dk3_5\0\dk4_5\0\dk5_5\0\dk6_5\0\tw0_5\83\tw1_5\0\tw2_5\0\tw3_5\0\tw4_5\0\tw5_5\0\tw6_5\0\tw7_5\0\tw8_5\0\te0_5\0\te1_5\0\te3_5\4\te2_5\0\te4_5\0\te5_5\0\te6_5\0\te7_5\0\te8_5\0\kw0_5\0\kw1_5\0\kw2_5\0\kw3_5\0\kw4_5\0\kw5_5\0\kw6_5\0\kw7_5\0\kw8_5\0\ke0_5\0\ke1_5\0\ke3_5\0\ke2_5\0\ke4_5\0\ke5_5\0\bw0_5\0\bw1_5\0\bw2_5\0\bw3_5\0\bw4_5\0\bw5_5\0\bw6_5\0\bw7_5\0\bw8_5\0\be0_5\0\be1_5\0\be3_5\0\be2_5\0\be4_5\0\be5_5\0\be8_5\0\be9_5\0\de6_5\0\de7_5\0\de8_5\0\sw0_5\2\sw1_5\0\sw2_5\0\sw3_5\0\sw4_5\0\sw5_5\0\sw6_5\0\sw7_5\0\sw8_5\0\se0_5\0\se1_5\0\se2_5\0\se3_5\0\se4_5\0\se5_5\0\hw0_5\1\hw1_5\0\hw2_5\0\hw3_5\0\hw4_5\0\hw5_5\0\hw6_5\0\hw7_5\0\hw8_5\0\he0_5\0\he1_5\0\he2_5\0\he3_5\0\he4_5\0\he5_5\0\pID_6\28999938\name_6\P. Lindholm\t_6\1\a_6\2\ctime_6\88\c_6\1\ip_6\127.0.0.1\ai_6\1\rs_6\2\cs_6\0\ss_6\0\ts_6\2\kills_6\0\deaths_6\0\cpc_6\1\cpa_6\0\cpd_6\0\ka_6\0\he_6\0\rev_6\0\rsp_6\0\rep_6\0\tre_6\0\drs_6\0\tmkl_6\0\tmdg_6\0\tmvd_6\0\su_6\0\ks_6\0\ds_6\0\rank_6\0\ban_6\0\kck_6\0\tco_6\0\tsl_6\0\tsm_6\88\tlw_6\0\ta0_6\0\ta1_6\0\ta2_6\88\ta3_6\0\ta4_6\0\ta5_6\0\ta6_6\0\ta7_6\0\ta8_6\0\ta9_6\0\ta10_6\0\ta11_6\0\ta12_6\0\ta13_6\0\tv0_6\0\tv1_6\0\tv2_6\0\tv3_6\0\tv4_6\67\tv5_6\0\tv6_6\0\tvp_6\0\kv0_6\0\kv1_6\0\kv2_6\0\kv3_6\0\kv4_6\0\kv5_6\0\kv6_6\0\bv0_6\0\bv1_6\0\bv2_6\0\bv3_6\0\bv4_6\0\bv5_6\0\bv6_6\0\kvr0_6\0\kvr1_6\0\kvr2_6\0\kvr3_6\0\kvr4_6\0\kvr5_6\0\kvr6_6\0\tk0_6\0\tk1_6\0\tk2_6\0\tk3_6\0\tk4_6\0\tk5_6\0\tk6_6\84\kk0_6\0\kk1_6\0\kk2_6\0\kk3_6\0\kk4_6\0\kk5_6\0\kk6_6\0\dk0_6\0\dk1_6\0\dk2_6\0\dk3_6\0\dk4_6\0\dk5_6\0\dk6_6\0\tw0_6\0\tw1_6\0\tw2_6\0\tw3_6\0\tw4_6\11\tw5_6\4\tw6_6\0\tw7_6\0\tw8_6\0\te0_6\0\te1_6\0\te3_6\0\te2_6\0\te4_6\0\te5_6\0\te6_6\0\te7_6\0\te8_6\0\kw0_6\0\kw1_6\0\kw2_6\0\kw3_6\0\kw4_6\0\kw5_6\0\kw6_6\0\kw7_6\0\kw8_6\0\ke0_6\0\ke1_6\0\ke3_6\0\ke2_6\0\ke4_6\0\ke5_6\0\bw0_6\0\bw1_6\0\bw2_6\0\bw3_6\0\bw4_6\0\bw5_6\0\bw6_6\0\bw7_6\0\bw8_6\0\be0_6\0\be1_6\0\be3_6\0\be2_6\0\be4_6\0\be5_6\0\be8_6\0\be9_6\0\de6_6\0\de7_6\0\de8_6\0\sw0_6\0\sw1_6\0\sw2_6\0\sw3_6\0\sw4_6\0\sw5_6\0\sw6_6\0\sw7_6\0\sw8_6\0\se0_6\0\se1_6\0\se2_6\0\se3_6\0\se4_6\0\se5_6\0\hw0_6\0\hw1_6\0\hw2_6\0\hw3_6\0\hw4_6\0\hw5_6\0\hw6_6\0\hw7_6\0\hw8_6\0\he0_6\0\he1_6\0\he2_6\0\he3_6\0\he4_6\0\he5_6\0\pID_7\28999965\name_7\J. Salt\t_7\1\a_7\2\ctime_7\88\c_7\1\ip_7\127.0.0.1\ai_7\1\rs_7\0\cs_7\0\ss_7\0\ts_7\0\kills_7\0\deaths_7\0\cpc_7\0\cpa_7\0\cpd_7\0\ka_7\0\he_7\0\rev_7\0\rsp_7\0\rep_7\0\tre_7\0\drs_7\0\tmkl_7\0\tmdg_7\0\tmvd_7\0\su_7\0\ks_7\0\ds_7\0\rank_7\0\ban_7\0\kck_7\0\tco_7\0\tsl_7\0\tsm_7\88\tlw_7\0\ta0_7\0\ta1_7\0\ta2_7\88\ta3_7\0\ta4_7\0\ta5_7\0\ta6_7\0\ta7_7\0\ta8_7\0\ta9_7\0\ta10_7\0\ta11_7\0\ta12_7\0\ta13_7\0\tv0_7\0\tv1_7\0\tv2_7\0\tv3_7\0\tv4_7\0\tv5_7\0\tv6_7\0\tvp_7\0\kv0_7\0\kv1_7\0\kv2_7\0\kv3_7\0\kv4_7\0\kv5_7\0\kv6_7\0\bv0_7\0\bv1_7\0\bv2_7\0\bv3_7\0\bv4_7\0\bv5_7\0\bv6_7\0\kvr0_7\0\kvr1_7\0\kvr2_7\0\kvr3_7\0\kvr4_7\0\kvr5_7\0\kvr6_7\0\tk0_7\0\tk1_7\0\tk2_7\88\tk3_7\0\tk4_7\0\tk5_7\0\tk6_7\0\kk0_7\0\kk1_7\0\kk2_7\0\kk3_7\0\kk4_7\0\kk5_7\0\kk6_7\0\dk0_7\0\dk1_7\0\dk2_7\0\dk3_7\0\dk4_7\0\dk5_7\0\dk6_7\0\tw0_7\0\tw1_7\0\tw2_7\0\tw3_7\0\tw4_7\0\tw5_7\0\tw6_7\0\tw7_7\0\tw8_7\88\te0_7\0\te1_7\0\te3_7\0\te2_7\0\te4_7\0\te5_7\0\te6_7\0\te7_7\0\te8_7\0\kw0_7\0\kw1_7\0\kw2_7\0\kw3_7\0\kw4_7\0\kw5_7\0\kw6_7\0\kw7_7\0\kw8_7\0\ke0_7\0\ke1_7\0\ke3_7\0\ke2_7\0\ke4_7\0\ke5_7\0\bw0_7\0\bw1_7\0\bw2_7\0\bw3_7\0\bw4_7\0\bw5_7\0\bw6_7\0\bw7_7\0\bw8_7\0\be0_7\0\be1_7\0\be3_7\0\be2_7\0\be4_7\0\be5_7\0\be8_7\0\be9_7\0\de6_7\0\de7_7\0\de8_7\0\sw0_7\0\sw1_7\0\sw2_7\0\sw3_7\0\sw4_7\0\sw5_7\0\sw6_7\0\sw7_7\0\sw8_7\0\se0_7\0\se1_7\0\se2_7\0\se3_7\0\se4_7\0\se5_7\0\hw0_7\0\hw1_7\0\hw2_7\0\hw3_7\0\hw4_7\0\hw5_7\0\hw6_7\0\hw7_7\0\hw8_7\0\he0_7\0\he1_7\0\he2_7\0\he3_7\0\he4_7\0\he5_7\0\pID_8\28999955\name_8\R. Edgren\t_8\1\a_8\2\ctime_8\88\c_8\1\ip_8\127.0.0.1\ai_8\1\rs_8\0\cs_8\0\ss_8\0\ts_8\0\kills_8\0\deaths_8\1\cpc_8\0\cpa_8\0\cpd_8\0\ka_8\0\he_8\0\rev_8\0\rsp_8\0\rep_8\0\tre_8\0\drs_8\0\tmkl_8\0\tmdg_8\0\tmvd_8\0\su_8\0\ks_8\0\ds_8\1\rank_8\0\ban_8\0\kck_8\0\tco_8\0\tsl_8\88\tsm_8\0\tlw_8\0\ta0_8\0\ta1_8\0\ta2_8\88\ta3_8\0\ta4_8\0\ta5_8\0\ta6_8\0\ta7_8\0\ta8_8\0\ta9_8\0\ta10_8\0\ta11_8\0\ta12_8\0\ta13_8\0\tv0_8\0\tv1_8\0\tv2_8\0\tv3_8\9\tv4_8\0\tv5_8\0\tv6_8\0\tvp_8\0\kv0_8\0\kv1_8\0\kv2_8\0\kv3_8\0\kv4_8\0\kv5_8\0\kv6_8\0\bv0_8\0\bv1_8\0\bv2_8\0\bv3_8\0\bv4_8\0\bv5_8\0\bv6_8\0\kvr0_8\0\kvr1_8\0\kvr2_8\0\kvr3_8\0\kvr4_8\0\kvr5_8\0\kvr6_8\0\tk0_8\0\tk1_8\0\tk2_8\77\tk3_8\0\tk4_8\0\tk5_8\0\tk6_8\0\kk0_8\0\kk1_8\0\kk2_8\0\kk3_8\0\kk4_8\0\kk5_8\0\kk6_8\0\dk0_8\0\dk1_8\0\dk2_8\1\dk3_8\0\dk4_8\0\dk5_8\0\dk6_8\0\tw0_8\0\tw1_8\0\tw2_8\0\tw3_8\0\tw4_8\0\tw5_8\0\tw6_8\0\tw7_8\0\tw8_8\58\te0_8\0\te1_8\0\te3_8\0\te2_8\0\te4_8\0\te5_8\0\te6_8\0\te7_8\0\te8_8\0\kw0_8\0\kw1_8\0\kw2_8\0\kw3_8\0\kw4_8\0\kw5_8\0\kw6_8\0\kw7_8\0\kw8_8\0\ke0_8\0\ke1_8\0\ke3_8\0\ke2_8\0\ke4_8\0\ke5_8\0\bw0_8\0\bw1_8\0\bw2_8\0\bw3_8\0\bw4_8\0\bw5_8\0\bw6_8\0\bw7_8\0\bw8_8\0\be0_8\0\be1_8\0\be3_8\0\be2_8\0\be4_8\0\be5_8\0\be8_8\0\be9_8\0\de6_8\0\de7_8\0\de8_8\0\sw0_8\0\sw1_8\0\sw2_8\0\sw3_8\0\sw4_8\0\sw5_8\0\sw6_8\0\sw7_8\0\sw8_8\0\se0_8\0\se1_8\0\se2_8\0\se3_8\0\se4_8\0\se5_8\0\hw0_8\0\hw1_8\0\hw2_8\0\hw3_8\0\hw4_8\0\hw5_8\0\hw6_8\0\hw7_8\0\hw8_8\0\he0_8\0\he1_8\0\he2_8\0\he3_8\0\he4_8\0\he5_8\0\pID_9\28999971\name_9\S. Decker\t_9\1\a_9\2\ctime_9\88\c_9\1\ip_9\127.0.0.1\ai_9\1\rs_9\0\cs_9\0\ss_9\0\ts_9\0\kills_9\0\deaths_9\0\cpc_9\0\cpa_9\0\cpd_9\0\ka_9\0\he_9\0\rev_9\0\rsp_9\0\rep_9\0\tre_9\0\drs_9\0\tmkl_9\0\tmdg_9\0\tmvd_9\0\su_9\0\ks_9\0\ds_9\0\rank_9\0\ban_9\0\kck_9\0\tco_9\0\tsl_9\0\tsm_9\88\tlw_9\0\ta0_9\0\ta1_9\0\ta2_9\88\ta3_9\0\ta4_9\0\ta5_9\0\ta6_9\0\ta7_9\0\ta8_9\0\ta9_9\0\ta10_9\0\ta11_9\0\ta12_9\0\ta13_9\0\tv0_9\0\tv1_9\0\tv2_9\0\tv3_9\0\tv4_9\0\tv5_9\0\tv6_9\0\tvp_9\0\kv0_9\0\kv1_9\0\kv2_9\0\kv3_9\0\kv4_9\0\kv5_9\0\kv6_9\0\bv0_9\0\bv1_9\0\bv2_9\0\bv3_9\0\bv4_9\0\bv5_9\0\bv6_9\0\kvr0_9\0\kvr1_9\0\kvr2_9\0\kvr3_9\0\kvr4_9\0\kvr5_9\0\kvr6_9\0\tk0_9\0\tk1_9\0\tk2_9\0\tk3_9\0\tk4_9\0\tk5_9\88\tk6_9\0\kk0_9\0\kk1_9\0\kk2_9\0\kk3_9\0\kk4_9\0\kk5_9\0\kk6_9\0\dk0_9\0\dk1_9\0\dk2_9\0\dk3_9\0\dk4_9\0\dk5_9\0\dk6_9\0\tw0_9\0\tw1_9\0\tw2_9\0\tw3_9\88\tw4_9\0\tw5_9\0\tw6_9\0\tw7_9\0\tw8_9\0\te0_9\0\te1_9\0\te3_9\0\te2_9\0\te4_9\0\te5_9\0\te6_9\0\te7_9\0\te8_9\0\kw0_9\0\kw1_9\0\kw2_9\0\kw3_9\0\kw4_9\0\kw5_9\0\kw6_9\0\kw7_9\0\kw8_9\0\ke0_9\0\ke1_9\0\ke3_9\0\ke2_9\0\ke4_9\0\ke5_9\0\bw0_9\0\bw1_9\0\bw2_9\0\bw3_9\0\bw4_9\0\bw5_9\0\bw6_9\0\bw7_9\0\bw8_9\0\be0_9\0\be1_9\0\be3_9\0\be2_9\0\be4_9\0\be5_9\0\be8_9\0\be9_9\0\de6_9\0\de7_9\0\de8_9\0\sw0_9\0\sw1_9\0\sw2_9\0\sw3_9\64\sw4_9\0\sw5_9\0\sw6_9\0\sw7_9\0\sw8_9\0\se0_9\0\se1_9\0\se2_9\0\se3_9\0\se4_9\0\se5_9\0\hw0_9\0\hw1_9\0\hw2_9\0\hw3_9\2\hw4_9\0\hw5_9\0\hw6_9\0\hw7_9\0\hw8_9\0\he0_9\0\he1_9\0\he2_9\0\he3_9\0\he4_9\0\he5_9\0\pID_10\28999928\name_10\J. Evans\t_10\1\a_10\2\ctime_10\73\c_10\1\ip_10\127.0.0.1\ai_10\1\rs_10\0\cs_10\0\ss_10\0\ts_10\0\kills_10\0\deaths_10\1\cpc_10\0\cpa_10\0\cpd_10\0\ka_10\0\he_10\0\rev_10\0\rsp_10\0\rep_10\0\tre_10\0\drs_10\0\tmkl_10\0\tmdg_10\0\tmvd_10\0\su_10\0\ks_10\0\ds_10\1\rank_10\0\ban_10\0\kck_10\0\tco_10\0\tsl_10\0\tsm_10\73\tlw_10\0\ta0_10\0\ta1_10\0\ta2_10\73\ta3_10\0\ta4_10\0\ta5_10\0\ta6_10\0\ta7_10\0\ta8_10\0\ta9_10\0\ta10_10\0\ta11_10\0\ta12_10\0\ta13_10\0\tv0_10\16\tv1_10\0\tv2_10\0\tv3_10\0\tv4_10\0\tv5_10\0\tv6_10\0\tvp_10\0\kv0_10\0\kv1_10\0\kv2_10\0\kv3_10\0\kv4_10\0\kv5_10\0\kv6_10\0\bv0_10\1\bv1_10\0\bv2_10\0\bv3_10\0\bv4_10\0\bv5_10\0\bv6_10\0\kvr0_10\0\kvr1_10\0\kvr2_10\0\kvr3_10\0\kvr4_10\0\kvr5_10\0\kvr6_10\0\tk0_10\0\tk1_10\0\tk2_10\0\tk3_10\73\tk4_10\0\tk5_10\0\tk6_10\0\kk0_10\0\kk1_10\0\kk2_10\0\kk3_10\0\kk4_10\0\kk5_10\0\kk6_10\0\dk0_10\0\dk1_10\0\dk2_10\0\dk3_10\1\dk4_10\0\dk5_10\0\dk6_10\0\tw0_10\54\tw1_10\0\tw2_10\0\tw3_10\0\tw4_10\0\tw5_10\0\tw6_10\0\tw7_10\16\tw8_10\0\te0_10\0\te1_10\0\te3_10\2\te2_10\0\te4_10\0\te5_10\0\te6_10\0\te7_10\0\te8_10\0\kw0_10\0\kw1_10\0\kw2_10\0\kw3_10\0\kw4_10\0\kw5_10\0\kw6_10\0\kw7_10\0\kw8_10\0\ke0_10\0\ke1_10\0\ke3_10\0\ke2_10\0\ke4_10\0\ke5_10\0\bw0_10\0\bw1_10\0\bw2_10\0\bw3_10\0\bw4_10\0\bw5_10\0\bw6_10\0\bw7_10\1\bw8_10\0\be0_10\0\be1_10\0\be3_10\0\be2_10\0\be4_10\0\be5_10\0\be8_10\0\be9_10\0\de6_10\0\de7_10\0\de8_10\0\sw0_10\12\sw1_10\0\sw2_10\0\sw3_10\0\sw4_10\0\sw5_10\0\sw6_10\0\sw7_10\80\sw8_10\0\se0_10\0\se1_10\0\se2_10\0\se3_10\0\se4_10\0\se5_10\0\hw0_10\0\hw1_10\0\hw2_10\0\hw3_10\0\hw4_10\0\hw5_10\0\hw6_10\0\hw7_10\1\hw8_10\0\he0_10\0\he1_10\0\he2_10\0\he3_10\0\he4_10\0\he5_10\0\pID_11\28999949\name_11\J. Gonzales\t_11\1\a_11\2\ctime_11\88\c_11\1\ip_11\127.0.0.1\ai_11\1\rs_11\4\cs_11\0\ss_11\4\ts_11\0\kills_11\2\deaths_11\0\cpc_11\0\cpa_11\0\cpd_11\0\ka_11\0\he_11\0\rev_11\0\rsp_11\0\rep_11\0\tre_11\0\drs_11\0\tmkl_11\0\tmdg_11\0\tmvd_11\0\su_11\0\ks_11\2\ds_11\0\rank_11\0\ban_11\0\kck_11\0\tco_11\0\tsl_11\0\tsm_11\88\tlw_11\0\ta0_11\0\ta1_11\0\ta2_11\88\ta3_11\0\ta4_11\0\ta5_11\0\ta6_11\0\ta7_11\0\ta8_11\0\ta9_11\0\ta10_11\0\ta11_11\0\ta12_11\0\ta13_11\0\mvns_11\28999902\mvks_11\1\mvns_11\28999946\mvks_11\1\erb_11\1\tv0_11\0\tv1_11\0\tv2_11\0\tv3_11\0\tv4_11\0\tv5_11\0\tv6_11\0\tvp_11\0\kv0_11\0\kv1_11\0\kv2_11\0\kv3_11\0\kv4_11\0\kv5_11\0\kv6_11\0\bv0_11\0\bv1_11\0\bv2_11\0\bv3_11\0\bv4_11\0\bv5_11\0\bv6_11\0\kvr0_11\0\kvr1_11\0\kvr2_11\0\kvr3_11\0\kvr4_11\0\kvr5_11\0\kvr6_11\0\tk0_11\87\tk1_11\0\tk2_11\0\tk3_11\0\tk4_11\0\tk5_11\0\tk6_11\0\kk0_11\2\kk1_11\0\kk2_11\0\kk3_11\0\kk4_11\0\kk5_11\0\kk6_11\0\dk0_11\0\dk1_11\0\dk2_11\0\dk3_11\0\dk4_11\0\dk5_11\0\dk6_11\0\tw0_11\0\tw1_11\0\tw2_11\0\tw3_11\0\tw4_11\0\tw5_11\10\tw6_11\13\tw7_11\63\tw8_11\0\te0_11\0\te1_11\0\te3_11\0\te2_11\0\te4_11\0\te5_11\0\te6_11\0\te7_11\0\te8_11\0\kw0_11\0\kw1_11\0\kw2_11\0\kw3_11\0\kw4_11\0\kw5_11\1\kw6_11\1\kw7_11\0\kw8_11\0\ke0_11\0\ke1_11\0\ke3_11\0\ke2_11\0\ke4_11\0\ke5_11\0\bw0_11\0\bw1_11\0\bw2_11\0\bw3_11\0\bw4_11\0\bw5_11\0\bw6_11\0\bw7_11\0\bw8_11\0\be0_11\0\be1_11\0\be3_11\0\be2_11\0\be4_11\0\be5_11\0\be8_11\0\be9_11\0\de6_11\0\de7_11\0\de8_11\0\sw0_11\0\sw1_11\0\sw2_11\0\sw3_11\0\sw4_11\0\sw5_11\13\sw6_11\3\sw7_11\30\sw8_11\0\se0_11\0\se1_11\0\se2_11\0\se3_11\0\se4_11\0\se5_11\0\hw0_11\0\hw1_11\0\hw2_11\0\hw3_11\0\hw4_11\0\hw5_11\2\hw6_11\1\hw7_11\0\hw8_11\0\he0_11\0\he1_11\0\he2_11\0\he3_11\0\he4_11\0\he5_11\0\pID_12\28999885\name_12\T. Dahl\t_12\1\a_12\2\ctime_12\88\c_12\1\ip_12\127.0.0.1\ai_12\1\rs_12\2\cs_12\0\ss_12\2\ts_12\0\kills_12\1\deaths_12\1\cpc_12\0\cpa_12\0\cpd_12\0\ka_12\0\he_12\0\rev_12\0\rsp_12\0\rep_12\0\tre_12\0\drs_12\0\tmkl_12\0\tmdg_12\0\tmvd_12\0\su_12\0\ks_12\1\ds_12\1\rank_12\0\ban_12\0\kck_12\0\tco_12\0\tsl_12\0\tsm_12\88\tlw_12\0\ta0_12\0\ta1_12\0\ta2_12\88\ta3_12\0\ta4_12\0\ta5_12\0\ta6_12\0\ta7_12\0\ta8_12\0\ta9_12\0\ta10_12\0\ta11_12\0\ta12_12\0\ta13_12\0\mvns_12\28999936\mvks_12\1\tv0_12\0\tv1_12\0\tv2_12\0\tv3_12\0\tv4_12\0\tv5_12\0\tv6_12\0\tvp_12\0\kv0_12\0\kv1_12\0\kv2_12\0\kv3_12\0\kv4_12\0\kv5_12\0\kv6_12\0\bv0_12\0\bv1_12\0\bv2_12\0\bv3_12\0\bv4_12\0\bv5_12\0\bv6_12\0\kvr0_12\0\kvr1_12\0\kvr2_12\0\kvr3_12\0\kvr4_12\0\kvr5_12\0\kvr6_12\0\tk0_12\0\tk1_12\63\tk2_12\0\tk3_12\0\tk4_12\0\tk5_12\13\tk6_12\0\kk0_12\0\kk1_12\1\kk2_12\0\kk3_12\0\kk4_12\0\kk5_12\0\kk6_12\0\dk0_12\0\dk1_12\1\dk2_12\0\dk3_12\0\dk4_12\0\dk5_12\0\dk6_12\0\tw0_12\53\tw1_12\9\tw2_12\0\tw3_12\8\tw4_12\0\tw5_12\3\tw6_12\0\tw7_12\0\tw8_12\0\te0_12\0\te1_12\0\te3_12\2\te2_12\0\te4_12\0\te5_12\0\te6_12\0\te7_12\0\te8_12\0\kw0_12\1\kw1_12\0\kw2_12\0\kw3_12\0\kw4_12\0\kw5_12\0\kw6_12\0\kw7_12\0\kw8_12\0\ke0_12\0\ke1_12\0\ke3_12\0\ke2_12\0\ke4_12\0\ke5_12\0\bw0_12\0\bw1_12\1\bw2_12\0\bw3_12\0\bw4_12\0\bw5_12\0\bw6_12\0\bw7_12\0\bw8_12\0\be0_12\0\be1_12\0\be3_12\0\be2_12\0\be4_12\0\be5_12\0\be8_12\0\be9_12\0\de6_12\0\de7_12\0\de8_12\0\sw0_12\25\sw1_12\0\sw2_12\0\sw3_12\0\sw4_12\0\sw5_12\2\sw6_12\0\sw7_12\0\sw8_12\0\se0_12\0\se1_12\0\se2_12\0\se3_12\0\se4_12\0\se5_12\0\hw0_12\1\hw1_12\0\hw2_12\0\hw3_12\0\hw4_12\0\hw5_12\0\hw6_12\0\hw7_12\0\hw8_12\0\he0_12\0\he1_12\0\he2_12\0\he3_12\0\he4_12\0\he5_12\0\pID_13\28999947\name_13\T. Karlsson\t_13\1\a_13\2\ctime_13\88\c_13\1\ip_13\127.0.0.1\ai_13\1\rs_13\2\cs_13\0\ss_13\2\ts_13\0\kills_13\1\deaths_13\0\cpc_13\0\cpa_13\0\cpd_13\0\ka_13\0\he_13\0\rev_13\0\rsp_13\0\rep_13\0\tre_13\0\drs_13\0\tmkl_13\0\tmdg_13\0\tmvd_13\0\su_13\0\ks_13\1\ds_13\0\rank_13\0\ban_13\0\kck_13\0\tco_13\0\tsl_13\88\tsm_13\0\tlw_13\0\ta0_13\0\ta1_13\0\ta2_13\88\ta3_13\0\ta4_13\0\ta5_13\0\ta6_13\0\ta7_13\0\ta8_13\0\ta9_13\0\ta10_13\0\ta11_13\0\ta12_13\0\ta13_13\0\mvns_13\28999990\mvks_13\1\tv0_13\0\tv1_13\0\tv2_13\0\tv3_13\0\tv4_13\0\tv5_13\0\tv6_13\0\tvp_13\0\kv0_13\0\kv1_13\0\kv2_13\0\kv3_13\0\kv4_13\0\kv5_13\0\kv6_13\0\bv0_13\0\bv1_13\0\bv2_13\0\bv3_13\0\bv4_13\0\bv5_13\0\bv6_13\0\kvr0_13\0\kvr1_13\0\kvr2_13\0\kvr3_13\0\kvr4_13\0\kvr5_13\0\kvr6_13\0\tk0_13\0\tk1_13\82\tk2_13\0\tk3_13\0\tk4_13\0\tk5_13\0\tk6_13\0\kk0_13\0\kk1_13\1\kk2_13\0\kk3_13\0\kk4_13\0\kk5_13\0\kk6_13\0\dk0_13\0\dk1_13\0\dk2_13\0\dk3_13\0\dk4_13\0\dk5_13\0\dk6_13\0\tw0_13\81\tw1_13\1\tw2_13\0\tw3_13\0\tw4_13\0\tw5_13\0\tw6_13\0\tw7_13\0\tw8_13\0\te0_13\0\te1_13\0\te3_13\0\te2_13\0\te4_13\0\te5_13\0\te6_13\0\te7_13\0\te8_13\0\kw0_13\1\kw1_13\0\kw2_13\0\kw3_13\0\kw4_13\0\kw5_13\0\kw6_13\0\kw7_13\0\kw8_13\0\ke0_13\0\ke1_13\0\ke3_13\0\ke2_13\0\ke4_13\0\ke5_13\0\bw0_13\0\bw1_13\0\bw2_13\0\bw3_13\0\bw4_13\0\bw5_13\0\bw6_13\0\bw7_13\0\bw8_13\0\be0_13\0\be1_13\0\be3_13\0\be2_13\0\be4_13\0\be5_13\0\be8_13\0\be9_13\0\de6_13\0\de7_13\0\de8_13\0\sw0_13\30\sw1_13\0\sw2_13\0\sw3_13\0\sw4_13\0\sw5_13\0\sw6_13\0\sw7_13\0\sw8_13\0\se0_13\0\se1_13\0\se2_13\0\se3_13\0\se4_13\0\se5_13\0\hw0_13\2\hw1_13\0\hw2_13\0\hw3_13\0\hw4_13\0\hw5_13\0\hw6_13\0\hw7_13\0\hw8_13\0\he0_13\0\he1_13\0\he2_13\0\he3_13\0\he4_13\0\he5_13\0\pID_14\28999933\name_14\E. Douridas\t_14\1\a_14\2\ctime_14\88\c_14\1\ip_14\127.0.0.1\ai_14\1\rs_14\0\cs_14\0\ss_14\0\ts_14\0\kills_14\0\deaths_14\0\cpc_14\0\cpa_14\0\cpd_14\0\ka_14\0\he_14\0\rev_14\0\rsp_14\0\rep_14\0\tre_14\0\drs_14\0\tmkl_14\0\tmdg_14\0\tmvd_14\0\su_14\0\ks_14\0\ds_14\0\rank_14\0\ban_14\0\kck_14\0\tco_14\0\tsl_14\0\tsm_14\88\tlw_14\0\ta0_14\0\ta1_14\0\ta2_14\88\ta3_14\0\ta4_14\0\ta5_14\0\ta6_14\0\ta7_14\0\ta8_14\0\ta9_14\0\ta10_14\0\ta11_14\0\ta12_14\0\ta13_14\0\tv0_14\0\tv1_14\0\tv2_14\0\tv3_14\0\tv4_14\0\tv5_14\0\tv6_14\0\tvp_14\0\kv0_14\0\kv1_14\0\kv2_14\0\kv3_14\0\kv4_14\0\kv5_14\0\kv6_14\0\bv0_14\0\bv1_14\0\bv2_14\0\bv3_14\0\bv4_14\0\bv5_14\0\bv6_14\0\kvr0_14\0\kvr1_14\0\kvr2_14\0\kvr3_14\0\kvr4_14\0\kvr5_14\0\kvr6_14\0\tk0_14\0\tk1_14\0\tk2_14\0\tk3_14\0\tk4_14\88\tk5_14\0\tk6_14\0\kk0_14\0\kk1_14\0\kk2_14\0\kk3_14\0\kk4_14\0\kk5_14\0\kk6_14\0\dk0_14\0\dk1_14\0\dk2_14\0\dk3_14\0\dk4_14\0\dk5_14\0\dk6_14\0\tw0_14\0\tw1_14\0\tw2_14\75\tw3_14\0\tw4_14\0\tw5_14\3\tw6_14\0\tw7_14\0\tw8_14\0\te0_14\0\te1_14\2\te3_14\7\te2_14\0\te4_14\0\te5_14\0\te6_14\0\te7_14\0\te8_14\0\kw0_14\0\kw1_14\0\kw2_14\0\kw3_14\0\kw4_14\0\kw5_14\0\kw6_14\0\kw7_14\0\kw8_14\0\ke0_14\0\ke1_14\0\ke3_14\0\ke2_14\0\ke4_14\0\ke5_14\0\bw0_14\0\bw1_14\0\bw2_14\0\bw3_14\0\bw4_14\0\bw5_14\0\bw6_14\0\bw7_14\0\bw8_14\0\be0_14\0\be1_14\0\be3_14\0\be2_14\0\be4_14\0\be5_14\0\be8_14\0\be9_14\0\de6_14\0\de7_14\0\de8_14\0\sw0_14\0\sw1_14\0\sw2_14\30\sw3_14\0\sw4_14\0\sw5_14\15\sw6_14\0\sw7_14\0\sw8_14\0\se0_14\0\se1_14\1\se2_14\0\se3_14\1\se4_14\0\se5_14\0\hw0_14\0\hw1_14\0\hw2_14\0\hw3_14\0\hw4_14\0\hw5_14\1\hw6_14\0\hw7_14\0\hw8_14\0\he0_14\0\he1_14\0\he2_14\0\he3_14\0\he4_14\0\he5_14\0\pID_15\28999880\name_15\C. Cyreus\t_15\1\a_15\2\ctime_15\88\c_15\1\ip_15\127.0.0.1\ai_15\1\rs_15\2\cs_15\0\ss_15\0\ts_15\2\kills_15\0\deaths_15\0\cpc_15\0\cpa_15\0\cpd_15\0\ka_15\0\he_15\0\rev_15\1\rsp_15\0\rep_15\0\tre_15\0\drs_15\0\tmkl_15\0\tmdg_15\0\tmvd_15\0\su_15\0\ks_15\0\ds_15\0\rank_15\0\ban_15\0\kck_15\0\tco_15\0\tsl_15\0\tsm_15\88\tlw_15\0\ta0_15\0\ta1_15\0\ta2_15\88\ta3_15\0\ta4_15\0\ta5_15\0\ta6_15\0\ta7_15\0\ta8_15\0\ta9_15\0\ta10_15\0\ta11_15\0\ta12_15\0\ta13_15\0\tv0_15\0\tv1_15\0\tv2_15\0\tv3_15\0\tv4_15\0\tv5_15\0\tv6_15\0\tvp_15\0\kv0_15\0\kv1_15\0\kv2_15\0\kv3_15\0\kv4_15\0\kv5_15\0\kv6_15\0\bv0_15\0\bv1_15\0\bv2_15\0\bv3_15\0\bv4_15\0\bv5_15\0\bv6_15\0\kvr0_15\0\kvr1_15\0\kvr2_15\0\kvr3_15\0\kvr4_15\0\kvr5_15\0\kvr6_15\0\tk0_15\0\tk1_15\0\tk2_15\0\tk3_15\88\tk4_15\0\tk5_15\0\tk6_15\0\kk0_15\0\kk1_15\0\kk2_15\0\kk3_15\0\kk4_15\0\kk5_15\0\kk6_15\0\dk0_15\0\dk1_15\0\dk2_15\0\dk3_15\0\dk4_15\0\dk5_15\0\dk6_15\0\tw0_15\73\tw1_15\0\tw2_15\0\tw3_15\0\tw4_15\0\tw5_15\1\tw6_15\0\tw7_15\0\tw8_15\0\te0_15\0\te1_15\0\te3_15\4\te2_15\0\te4_15\9\te5_15\0\te6_15\0\te7_15\0\te8_15\0\kw0_15\0\kw1_15\0\kw2_15\0\kw3_15\0\kw4_15\0\kw5_15\0\kw6_15\0\kw7_15\0\kw8_15\0\ke0_15\0\ke1_15\0\ke3_15\0\ke2_15\0\ke4_15\0\ke5_15\0\bw0_15\0\bw1_15\0\bw2_15\0\bw3_15\0\bw4_15\0\bw5_15\0\bw6_15\0\bw7_15\0\bw8_15\0\be0_15\0\be1_15\0\be3_15\0\be2_15\0\be4_15\0\be5_15\0\be8_15\0\be9_15\0\de6_15\0\de7_15\0\de8_15\0\sw0_15\30\sw1_15\0\sw2_15\0\sw3_15\0\sw4_15\0\sw5_15\3\sw6_15\0\sw7_15\0\sw8_15\0\se0_15\0\se1_15\0\se2_15\0\se3_15\0\se4_15\1\se5_15\0\hw0_15\1\hw1_15\0\hw2_15\0\hw3_15\0\hw4_15\0\hw5_15\0\hw6_15\0\hw7_15\0\hw8_15\0\he0_15\0\he1_15\0\he2_15\0\he3_15\0\he4_15\1\he5_15\0\pID_16\28999889\name_16\J. Vifian\t_16\2\a_16\0\ctime_16\88\c_16\1\ip_16\127.0.0.1\ai_16\1\rs_16\0\cs_16\0\ss_16\0\ts_16\0\kills_16\0\deaths_16\0\cpc_16\0\cpa_16\0\cpd_16\0\ka_16\0\he_16\0\rev_16\0\rsp_16\0\rep_16\0\tre_16\0\drs_16\0\tmkl_16\0\tmdg_16\0\tmvd_16\0\su_16\0\ks_16\0\ds_16\0\rank_16\0\ban_16\0\kck_16\0\tco_16\0\tsl_16\88\tsm_16\0\tlw_16\0\ta0_16\88\ta1_16\0\ta2_16\0\ta3_16\0\ta4_16\0\ta5_16\0\ta6_16\0\ta7_16\0\ta8_16\0\ta9_16\0\ta10_16\0\ta11_16\0\ta12_16\0\ta13_16\0\tv0_16\0\tv1_16\0\tv2_16\0\tv3_16\0\tv4_16\0\tv5_16\0\tv6_16\0\tvp_16\0\kv0_16\0\kv1_16\0\kv2_16\0\kv3_16\0\kv4_16\0\kv5_16\0\kv6_16\0\bv0_16\0\bv1_16\0\bv2_16\0\bv3_16\0\bv4_16\0\bv5_16\0\bv6_16\0\kvr0_16\0\kvr1_16\0\kvr2_16\0\kvr3_16\0\kvr4_16\0\kvr5_16\0\kvr6_16\0\tk0_16\0\tk1_16\0\tk2_16\0\tk3_16\0\tk4_16\0\tk5_16\88\tk6_16\0\kk0_16\0\kk1_16\0\kk2_16\0\kk3_16\0\kk4_16\0\kk5_16\0\kk6_16\0\dk0_16\0\dk1_16\0\dk2_16\0\dk3_16\0\dk4_16\0\dk5_16\0\dk6_16\0\tw0_16\0\tw1_16\0\tw2_16\0\tw3_16\87\tw4_16\0\tw5_16\0\tw6_16\0\tw7_16\0\tw8_16\0\te0_16\0\te1_16\0\te3_16\0\te2_16\0\te4_16\0\te5_16\0\te6_16\0\te7_16\0\te8_16\0\kw0_16\0\kw1_16\0\kw2_16\0\kw3_16\0\kw4_16\0\kw5_16\0\kw6_16\0\kw7_16\0\kw8_16\0\ke0_16\0\ke1_16\0\ke3_16\0\ke2_16\0\ke4_16\0\ke5_16\0\bw0_16\0\bw1_16\0\bw2_16\0\bw3_16\0\bw4_16\0\bw5_16\0\bw6_16\0\bw7_16\0\bw8_16\0\be0_16\0\be1_16\0\be3_16\0\be2_16\0\be4_16\0\be5_16\0\be8_16\0\be9_16\0\de6_16\0\de7_16\0\de8_16\0\sw0_16\0\sw1_16\0\sw2_16\0\sw3_16\73\sw4_16\0\sw5_16\0\sw6_16\0\sw7_16\0\sw8_16\0\se0_16\0\se1_16\0\se2_16\0\se3_16\0\se4_16\0\se5_16\0\hw0_16\0\hw1_16\0\hw2_16\0\hw3_16\0\hw4_16\0\hw5_16\0\hw6_16\0\hw7_16\0\hw8_16\0\he0_16\0\he1_16\0\he2_16\0\he3_16\0\he4_16\0\he5_16\0\pID_17\28999967\name_17\P.K. Johansson\t_17\2\a_17\0\ctime_17\88\c_17\1\ip_17\127.0.0.1\ai_17\1\rs_17\0\cs_17\0\ss_17\0\ts_17\0\kills_17\0\deaths_17\0\cpc_17\0\cpa_17\0\cpd_17\0\ka_17\0\he_17\0\rev_17\0\rsp_17\0\rep_17\0\tre_17\0\drs_17\0\tmkl_17\0\tmdg_17\0\tmvd_17\0\su_17\0\ks_17\0\ds_17\0\rank_17\0\ban_17\0\kck_17\0\tco_17\0\tsl_17\0\tsm_17\88\tlw_17\0\ta0_17\88\ta1_17\0\ta2_17\0\ta3_17\0\ta4_17\0\ta5_17\0\ta6_17\0\ta7_17\0\ta8_17\0\ta9_17\0\ta10_17\0\ta11_17\0\ta12_17\0\ta13_17\0\tv0_17\0\tv1_17\0\tv2_17\0\tv3_17\0\tv4_17\0\tv5_17\0\tv6_17\0\tvp_17\0\kv0_17\0\kv1_17\0\kv2_17\0\kv3_17\0\kv4_17\0\kv5_17\0\kv6_17\0\bv0_17\0\bv1_17\0\bv2_17\0\bv3_17\0\bv4_17\0\bv5_17\0\bv6_17\0\kvr0_17\0\kvr1_17\0\kvr2_17\0\kvr3_17\0\kvr4_17\0\kvr5_17\0\kvr6_17\0\tk0_17\0\tk1_17\0\tk2_17\0\tk3_17\88\tk4_17\0\tk5_17\0\tk6_17\0\kk0_17\0\kk1_17\0\kk2_17\0\kk3_17\0\kk4_17\0\kk5_17\0\kk6_17\0\dk0_17\0\dk1_17\0\dk2_17\0\dk3_17\0\dk4_17\0\dk5_17\0\dk6_17\0\tw0_17\87\tw1_17\0\tw2_17\0\tw3_17\0\tw4_17\0\tw5_17\0\tw6_17\0\tw7_17\0\tw8_17\0\te0_17\0\te1_17\0\te3_17\1\te2_17\0\te4_17\0\te5_17\0\te6_17\0\te7_17\0\te8_17\0\kw0_17\0\kw1_17\0\kw2_17\0\kw3_17\0\kw4_17\0\kw5_17\0\kw6_17\0\kw7_17\0\kw8_17\0\ke0_17\0\ke1_17\0\ke3_17\0\ke2_17\0\ke4_17\0\ke5_17\0\bw0_17\0\bw1_17\0\bw2_17\0\bw3_17\0\bw4_17\0\bw5_17\0\bw6_17\0\bw7_17\0\bw8_17\0\be0_17\0\be1_17\0\be3_17\0\be2_17\0\be4_17\0\be5_17\0\be8_17\0\be9_17\0\de6_17\0\de7_17\0\de8_17\0\sw0_17\30\sw1_17\0\sw2_17\0\sw3_17\0\sw4_17\0\sw5_17\0\sw6_17\0\sw7_17\0\sw8_17\0\se0_17\0\se1_17\0\se2_17\0\se3_17\0\se4_17\0\se5_17\0\hw0_17\0\hw1_17\0\hw2_17\0\hw3_17\0\hw4_17\0\hw5_17\0\hw6_17\0\hw7_17\0\hw8_17\0\he0_17\0\he1_17\0\he2_17\0\he3_17\0\he4_17\0\he5_17\0\pID_18\28999969\name_18\S. Wallberg\t_18\2\a_18\0\ctime_18\59\c_18\1\ip_18\127.0.0.1\ai_18\1\rs_18\1\cs_18\0\ss_18\0\ts_18\1\kills_18\0\deaths_18\0\cpc_18\0\cpa_18\0\cpd_18\0\ka_18\1\he_18\0\rev_18\0\rsp_18\0\rep_18\0\tre_18\0\drs_18\0\tmkl_18\0\tmdg_18\0\tmvd_18\0\su_18\0\ks_18\0\ds_18\0\rank_18\0\ban_18\0\kck_18\0\tco_18\0\tsl_18\0\tsm_18\72\tlw_18\-13\ta0_18\59\ta1_18\0\ta2_18\0\ta3_18\0\ta4_18\0\ta5_18\0\ta6_18\0\ta7_18\0\ta8_18\0\ta9_18\0\ta10_18\0\ta11_18\0\ta12_18\0\ta13_18\0\tv0_18\0\tv1_18\0\tv2_18\0\tv3_18\0\tv4_18\10\tv5_18\0\tv6_18\0\tvp_18\0\kv0_18\0\kv1_18\0\kv2_18\0\kv3_18\0\kv4_18\0\kv5_18\0\kv6_18\0\bv0_18\0\bv1_18\0\bv2_18\0\bv3_18\0\bv4_18\0\bv5_18\0\bv6_18\0\kvr0_18\0\kvr1_18\0\kvr2_18\0\kvr3_18\0\kvr4_18\0\kvr5_18\0\kvr6_18\0\tk0_18\0\tk1_18\13\tk2_18\0\tk3_18\0\tk4_18\0\tk5_18\59\tk6_18\0\kk0_18\0\kk1_18\0\kk2_18\0\kk3_18\0\kk4_18\0\kk5_18\0\kk6_18\0\dk0_18\0\dk1_18\0\dk2_18\0\dk3_18\0\dk4_18\0\dk5_18\0\dk6_18\0\tw0_18\3\tw1_18\0\tw2_18\0\tw3_18\59\tw4_18\0\tw5_18\0\tw6_18\0\tw7_18\0\tw8_18\0\te0_18\0\te1_18\0\te3_18\0\te2_18\0\te4_18\0\te5_18\0\te6_18\0\te7_18\0\te8_18\0\kw0_18\0\kw1_18\0\kw2_18\0\kw3_18\0\kw4_18\0\kw5_18\0\kw6_18\0\kw7_18\0\kw8_18\0\ke0_18\0\ke1_18\0\ke3_18\0\ke2_18\0\ke4_18\0\ke5_18\0\bw0_18\0\bw1_18\0\bw2_18\0\bw3_18\0\bw4_18\0\bw5_18\0\bw6_18\0\bw7_18\0\bw8_18\0\be0_18\0\be1_18\0\be3_18\0\be2_18\0\be4_18\0\be5_18\0\be8_18\0\be9_18\0\de6_18\0\de7_18\0\de8_18\0\sw0_18\0\sw1_18\0\sw2_18\0\sw3_18\23\sw4_18\0\sw5_18\0\sw6_18\0\sw7_18\0\sw8_18\0\se0_18\0\se1_18\0\se2_18\0\se3_18\0\se4_18\0\se5_18\0\hw0_18\0\hw1_18\0\hw2_18\0\hw3_18\1\hw4_18\0\hw5_18\0\hw6_18\0\hw7_18\0\hw8_18\0\he0_18\0\he1_18\0\he2_18\0\he3_18\0\he4_18\0\he5_18\0\pID_19\28999899\name_19\F. Lindblom\t_19\2\a_19\0\ctime_19\88\c_19\1\ip_19\127.0.0.1\ai_19\1\rs_19\0\cs_19\0\ss_19\0\ts_19\0\kills_19\0\deaths_19\0\cpc_19\0\cpa_19\0\cpd_19\0\ka_19\0\he_19\0\rev_19\0\rsp_19\0\rep_19\0\tre_19\0\drs_19\0\tmkl_19\0\tmdg_19\0\tmvd_19\0\su_19\0\ks_19\0\ds_19\0\rank_19\0\ban_19\0\kck_19\0\tco_19\0\tsl_19\0\tsm_19\88\tlw_19\0\ta0_19\88\ta1_19\0\ta2_19\0\ta3_19\0\ta4_19\0\ta5_19\0\ta6_19\0\ta7_19\0\ta8_19\0\ta9_19\0\ta10_19\0\ta11_19\0\ta12_19\0\ta13_19\0\tv0_19\0\tv1_19\0\tv2_19\0\tv3_19\0\tv4_19\0\tv5_19\0\tv6_19\0\tvp_19\0\kv0_19\0\kv1_19\0\kv2_19\0\kv3_19\0\kv4_19\0\kv5_19\0\kv6_19\0\bv0_19\0\bv1_19\0\bv2_19\0\bv3_19\0\bv4_19\0\bv5_19\0\bv6_19\0\kvr0_19\0\kvr1_19\0\kvr2_19\0\kvr3_19\0\kvr4_19\0\kvr5_19\0\kvr6_19\0\tk0_19\0\tk1_19\0\tk2_19\0\tk3_19\0\tk4_19\88\tk5_19\0\tk6_19\0\kk0_19\0\kk1_19\0\kk2_19\0\kk3_19\0\kk4_19\0\kk5_19\0\kk6_19\0\dk0_19\0\dk1_19\0\dk2_19\0\dk3_19\0\dk4_19\0\dk5_19\0\dk6_19\0\tw0_19\0\tw1_19\0\tw2_19\86\tw3_19\0\tw4_19\0\tw5_19\0\tw6_19\0\tw7_19\0\tw8_19\0\te0_19\0\te1_19\1\te3_19\0\te2_19\0\te4_19\0\te5_19\0\te6_19\0\te7_19\0\te8_19\0\kw0_19\0\kw1_19\0\kw2_19\0\kw3_19\0\kw4_19\0\kw5_19\0\kw6_19\0\kw7_19\0\kw8_19\0\ke0_19\0\ke1_19\0\ke3_19\0\ke2_19\0\ke4_19\0\ke5_19\0\bw0_19\0\bw1_19\0\bw2_19\0\bw3_19\0\bw4_19\0\bw5_19\0\bw6_19\0\bw7_19\0\bw8_19\0\be0_19\0\be1_19\0\be3_19\0\be2_19\0\be4_19\0\be5_19\0\be8_19\0\be9_19\0\de6_19\0\de7_19\0\de8_19\0\sw0_19\0\sw1_19\0\sw2_19\16\sw3_19\0\sw4_19\0\sw5_19\0\sw6_19\0\sw7_19\0\sw8_19\0\se0_19\0\se1_19\1\se2_19\0\se3_19\0\se4_19\0\se5_19\0\hw0_19\0\hw1_19\0\hw2_19\1\hw3_19\0\hw4_19\0\hw5_19\0\hw6_19\0\hw7_19\0\hw8_19\0\he0_19\0\he1_19\0\he2_19\0\he3_19\0\he4_19\0\he5_19\0\pID_20\28999887\name_20\K. Lee\t_20\2\a_20\0\ctime_20\88\c_20\1\ip_20\127.0.0.1\ai_20\1\rs_20\0\cs_20\0\ss_20\0\ts_20\0\kills_20\0\deaths_20\0\cpc_20\0\cpa_20\0\cpd_20\0\ka_20\0\he_20\0\rev_20\0\rsp_20\0\rep_20\0\tre_20\0\drs_20\0\tmkl_20\0\tmdg_20\0\tmvd_20\0\su_20\0\ks_20\0\ds_20\0\rank_20\0\ban_20\0\kck_20\0\tco_20\0\tsl_20\88\tsm_20\0\tlw_20\0\ta0_20\88\ta1_20\0\ta2_20\0\ta3_20\0\ta4_20\0\ta5_20\0\ta6_20\0\ta7_20\0\ta8_20\0\ta9_20\0\ta10_20\0\ta11_20\0\ta12_20\0\ta13_20\0\tv0_20\0\tv1_20\0\tv2_20\0\tv3_20\0\tv4_20\0\tv5_20\0\tv6_20\0\tvp_20\0\kv0_20\0\kv1_20\0\kv2_20\0\kv3_20\0\kv4_20\0\kv5_20\0\kv6_20\0\bv0_20\0\bv1_20\0\bv2_20\0\bv3_20\0\bv4_20\0\bv5_20\0\bv6_20\0\kvr0_20\0\kvr1_20\0\kvr2_20\0\kvr3_20\0\kvr4_20\0\kvr5_20\0\kvr6_20\0\tk0_20\0\tk1_20\0\tk2_20\0\tk3_20\0\tk4_20\88\tk5_20\0\tk6_20\0\kk0_20\0\kk1_20\0\kk2_20\0\kk3_20\0\kk4_20\0\kk5_20\0\kk6_20\0\dk0_20\0\dk1_20\0\dk2_20\0\dk3_20\0\dk4_20\0\dk5_20\0\dk6_20\0\tw0_20\0\tw1_20\0\tw2_20\86\tw3_20\0\tw4_20\0\tw5_20\0\tw6_20\0\tw7_20\0\tw8_20\0\te0_20\0\te1_20\1\te3_20\0\te2_20\0\te4_20\0\te5_20\0\te6_20\0\te7_20\0\te8_20\0\kw0_20\0\kw1_20\0\kw2_20\0\kw3_20\0\kw4_20\0\kw5_20\0\kw6_20\0\kw7_20\0\kw8_20\0\ke0_20\0\ke1_20\0\ke3_20\0\ke2_20\0\ke4_20\0\ke5_20\0\bw0_20\0\bw1_20\0\bw2_20\0\bw3_20\0\bw4_20\0\bw5_20\0\bw6_20\0\bw7_20\0\bw8_20\0\be0_20\0\be1_20\0\be3_20\0\be2_20\0\be4_20\0\be5_20\0\be8_20\0\be9_20\0\de6_20\0\de7_20\0\de8_20\0\sw0_20\0\sw1_20\0\sw2_20\6\sw3_20\0\sw4_20\0\sw5_20\0\sw6_20\0\sw7_20\0\sw8_20\0\se0_20\0\se1_20\1\se2_20\0\se3_20\0\se4_20\0\se5_20\0\hw0_20\0\hw1_20\0\hw2_20\0\hw3_20\0\hw4_20\0\hw5_20\0\hw6_20\0\hw7_20\0\hw8_20\0\he0_20\0\he1_20\0\he2_20\0\he3_20\0\he4_20\0\he5_20\0\pID_21\28999979\name_21\B. Smith\t_21\2\a_21\0\ctime_21\88\c_21\1\ip_21\127.0.0.1\ai_21\1\rs_21\0\cs_21\0\ss_21\0\ts_21\0\kills_21\0\deaths_21\0\cpc_21\0\cpa_21\0\cpd_21\0\ka_21\0\he_21\0\rev_21\0\rsp_21\0\rep_21\0\tre_21\0\drs_21\0\tmkl_21\0\tmdg_21\0\tmvd_21\0\su_21\0\ks_21\0\ds_21\0\rank_21\0\ban_21\0\kck_21\0\tco_21\0\tsl_21\0\tsm_21\88\tlw_21\0\ta0_21\88\ta1_21\0\ta2_21\0\ta3_21\0\ta4_21\0\ta5_21\0\ta6_21\0\ta7_21\0\ta8_21\0\ta9_21\0\ta10_21\0\ta11_21\0\ta12_21\0\ta13_21\0\tv0_21\0\tv1_21\0\tv2_21\0\tv3_21\0\tv4_21\0\tv5_21\0\tv6_21\0\tvp_21\0\kv0_21\0\kv1_21\0\kv2_21\0\kv3_21\0\kv4_21\0\kv5_21\0\kv6_21\0\bv0_21\0\bv1_21\0\bv2_21\0\bv3_21\0\bv4_21\0\bv5_21\0\bv6_21\0\kvr0_21\0\kvr1_21\0\kvr2_21\0\kvr3_21\0\kvr4_21\0\kvr5_21\0\kvr6_21\0\tk0_21\0\tk1_21\0\tk2_21\0\tk3_21\88\tk4_21\0\tk5_21\0\tk6_21\0\kk0_21\0\kk1_21\0\kk2_21\0\kk3_21\0\kk4_21\0\kk5_21\0\kk6_21\0\dk0_21\0\dk1_21\0\dk2_21\0\dk3_21\0\dk4_21\0\dk5_21\0\dk6_21\0\tw0_21\84\tw1_21\0\tw2_21\0\tw3_21\0\tw4_21\0\tw5_21\0\tw6_21\0\tw7_21\0\tw8_21\0\te0_21\0\te1_21\0\te3_21\0\te2_21\0\te4_21\0\te5_21\0\te6_21\0\te7_21\0\te8_21\0\kw0_21\0\kw1_21\0\kw2_21\0\kw3_21\0\kw4_21\0\kw5_21\0\kw6_21\0\kw7_21\0\kw8_21\0\ke0_21\0\ke1_21\0\ke3_21\0\ke2_21\0\ke4_21\0\ke5_21\0\bw0_21\0\bw1_21\0\bw2_21\0\bw3_21\0\bw4_21\0\bw5_21\0\bw6_21\0\bw7_21\0\bw8_21\0\be0_21\0\be1_21\0\be3_21\0\be2_21\0\be4_21\0\be5_21\0\be8_21\0\be9_21\0\de6_21\0\de7_21\0\de8_21\0\sw0_21\12\sw1_21\0\sw2_21\0\sw3_21\0\sw4_21\0\sw5_21\0\sw6_21\0\sw7_21\0\sw8_21\0\se0_21\0\se1_21\0\se2_21\0\se3_21\0\se4_21\0\se5_21\0\hw0_21\0\hw1_21\0\hw2_21\0\hw3_21\0\hw4_21\0\hw5_21\0\hw6_21\0\hw7_21\0\hw8_21\0\he0_21\0\he1_21\0\he2_21\0\he3_21\0\he4_21\0\he5_21\0\pID_22\28999875\name_22\C. Grass\t_22\2\a_22\0\ctime_22\88\c_22\1\ip_22\127.0.0.1\ai_22\1\rs_22\0\cs_22\0\ss_22\0\ts_22\0\kills_22\0\deaths_22\0\cpc_22\0\cpa_22\0\cpd_22\0\ka_22\0\he_22\0\rev_22\0\rsp_22\0\rep_22\0\tre_22\0\drs_22\0\tmkl_22\0\tmdg_22\0\tmvd_22\0\su_22\0\ks_22\0\ds_22\0\rank_22\0\ban_22\0\kck_22\0\tco_22\0\tsl_22\0\tsm_22\88\tlw_22\0\ta0_22\88\ta1_22\0\ta2_22\0\ta3_22\0\ta4_22\0\ta5_22\0\ta6_22\0\ta7_22\0\ta8_22\0\ta9_22\0\ta10_22\0\ta11_22\0\ta12_22\0\ta13_22\0\tv0_22\0\tv1_22\0\tv2_22\0\tv3_22\0\tv4_22\34\tv5_22\0\tv6_22\0\tvp_22\0\kv0_22\0\kv1_22\0\kv2_22\0\kv3_22\0\kv4_22\0\kv5_22\0\kv6_22\0\bv0_22\0\bv1_22\0\bv2_22\0\bv3_22\0\bv4_22\0\bv5_22\0\bv6_22\0\kvr0_22\0\kvr1_22\0\kvr2_22\0\kvr3_22\0\kvr4_22\0\kvr5_22\0\kvr6_22\0\tk0_22\88\tk1_22\0\tk2_22\0\tk3_22\0\tk4_22\0\tk5_22\0\tk6_22\0\kk0_22\0\kk1_22\0\kk2_22\0\kk3_22\0\kk4_22\0\kk5_22\0\kk6_22\0\dk0_22\0\dk1_22\0\dk2_22\0\dk3_22\0\dk4_22\0\dk5_22\0\dk6_22\0\tw0_22\0\tw1_22\0\tw2_22\0\tw3_22\0\tw4_22\0\tw5_22\0\tw6_22\0\tw7_22\54\tw8_22\0\te0_22\0\te1_22\0\te3_22\0\te2_22\0\te4_22\0\te5_22\0\te6_22\0\te7_22\0\te8_22\0\kw0_22\0\kw1_22\0\kw2_22\0\kw3_22\0\kw4_22\0\kw5_22\0\kw6_22\0\kw7_22\0\kw8_22\0\ke0_22\0\ke1_22\0\ke3_22\0\ke2_22\0\ke4_22\0\ke5_22\0\bw0_22\0\bw1_22\0\bw2_22\0\bw3_22\0\bw4_22\0\bw5_22\0\bw6_22\0\bw7_22\0\bw8_22\0\be0_22\0\be1_22\0\be3_22\0\be2_22\0\be4_22\0\be5_22\0\be8_22\0\be9_22\0\de6_22\0\de7_22\0\de8_22\0\sw0_22\0\sw1_22\0\sw2_22\0\sw3_22\0\sw4_22\0\sw5_22\0\sw6_22\0\sw7_22\0\sw8_22\0\se0_22\0\se1_22\0\se2_22\0\se3_22\0\se4_22\0\se5_22\0\hw0_22\0\hw1_22\0\hw2_22\0\hw3_22\0\hw4_22\0\hw5_22\0\hw6_22\0\hw7_22\0\hw8_22\0\he0_22\0\he1_22\0\he2_22\0\he3_22\0\he4_22\0\he5_22\0\pID_23\28999920\name_23\M. Bagge\t_23\2\a_23\0\ctime_23\88\c_23\1\ip_23\127.0.0.1\ai_23\1\rs_23\0\cs_23\0\ss_23\0\ts_23\0\kills_23\0\deaths_23\0\cpc_23\0\cpa_23\0\cpd_23\0\ka_23\0\he_23\0\rev_23\0\rsp_23\0\rep_23\0\tre_23\0\drs_23\0\tmkl_23\0\tmdg_23\0\tmvd_23\0\su_23\0\ks_23\0\ds_23\0\rank_23\0\ban_23\0\kck_23\0\tco_23\0\tsl_23\0\tsm_23\88\tlw_23\0\ta0_23\88\ta1_23\0\ta2_23\0\ta3_23\0\ta4_23\0\ta5_23\0\ta6_23\0\ta7_23\0\ta8_23\0\ta9_23\0\ta10_23\0\ta11_23\0\ta12_23\0\ta13_23\0\tv0_23\0\tv1_23\0\tv2_23\0\tv3_23\0\tv4_23\26\tv5_23\0\tv6_23\0\tvp_23\0\kv0_23\0\kv1_23\0\kv2_23\0\kv3_23\0\kv4_23\0\kv5_23\0\kv6_23\0\bv0_23\0\bv1_23\0\bv2_23\0\bv3_23\0\bv4_23\0\bv5_23\0\bv6_23\0\kvr0_23\0\kvr1_23\0\kvr2_23\0\kvr3_23\0\kvr4_23\0\kvr5_23\0\kvr6_23\0\tk0_23\0\tk1_23\0\tk2_23\0\tk3_23\0\tk4_23\0\tk5_23\88\tk6_23\0\kk0_23\0\kk1_23\0\kk2_23\0\kk3_23\0\kk4_23\0\kk5_23\0\kk6_23\0\dk0_23\0\dk1_23\0\dk2_23\0\dk3_23\0\dk4_23\0\dk5_23\0\dk6_23\0\tw0_23\0\tw1_23\0\tw2_23\0\tw3_23\62\tw4_23\0\tw5_23\0\tw6_23\0\tw7_23\0\tw8_23\0\te0_23\0\te1_23\0\te3_23\0\te2_23\0\te4_23\0\te5_23\0\te6_23\0\te7_23\0\te8_23\0\kw0_23\0\kw1_23\0\kw2_23\0\kw3_23\0\kw4_23\0\kw5_23\0\kw6_23\0\kw7_23\0\kw8_23\0\ke0_23\0\ke1_23\0\ke3_23\0\ke2_23\0\ke4_23\0\ke5_23\0\bw0_23\0\bw1_23\0\bw2_23\0\bw3_23\0\bw4_23\0\bw5_23\0\bw6_23\0\bw7_23\0\bw8_23\0\be0_23\0\be1_23\0\be3_23\0\be2_23\0\be4_23\0\be5_23\0\be8_23\0\be9_23\0\de6_23\0\de7_23\0\de8_23\0\sw0_23\0\sw1_23\0\sw2_23\0\sw3_23\0\sw4_23\0\sw5_23\0\sw6_23\0\sw7_23\0\sw8_23\0\se0_23\0\se1_23\0\se2_23\0\se3_23\0\se4_23\0\se5_23\0\hw0_23\0\hw1_23\0\hw2_23\0\hw3_23\0\hw4_23\0\hw5_23\0\hw6_23\0\hw7_23\0\hw8_23\0\he0_23\0\he1_23\0\he2_23\0\he3_23\0\he4_23\0\he5_23\0\pID_24\28999935\name_24\J. VanRooyen\t_24\2\a_24\0\ctime_24\88\c_24\1\ip_24\127.0.0.1\ai_24\1\rs_24\0\cs_24\0\ss_24\0\ts_24\0\kills_24\0\deaths_24\1\cpc_24\0\cpa_24\0\cpd_24\0\ka_24\0\he_24\0\rev_24\0\rsp_24\0\rep_24\0\tre_24\0\drs_24\0\tmkl_24\0\tmdg_24\0\tmvd_24\0\su_24\0\ks_24\0\ds_24\1\rank_24\0\ban_24\0\kck_24\0\tco_24\0\tsl_24\88\tsm_24\0\tlw_24\0\ta0_24\88\ta1_24\0\ta2_24\0\ta3_24\0\ta4_24\0\ta5_24\0\ta6_24\0\ta7_24\0\ta8_24\0\ta9_24\0\ta10_24\0\ta11_24\0\ta12_24\0\ta13_24\0\tv0_24\0\tv1_24\0\tv2_24\0\tv3_24\0\tv4_24\0\tv5_24\0\tv6_24\0\tvp_24\0\kv0_24\0\kv1_24\0\kv2_24\0\kv3_24\0\kv4_24\0\kv5_24\0\kv6_24\0\bv0_24\0\bv1_24\0\bv2_24\0\bv3_24\0\bv4_24\0\bv5_24\0\bv6_24\0\kvr0_24\0\kvr1_24\0\kvr2_24\0\kvr3_24\0\kvr4_24\0\kvr5_24\0\kvr6_24\0\tk0_24\0\tk1_24\0\tk2_24\0\tk3_24\0\tk4_24\26\tk5_24\0\tk6_24\51\kk0_24\0\kk1_24\0\kk2_24\0\kk3_24\0\kk4_24\0\kk5_24\0\kk6_24\0\dk0_24\0\dk1_24\0\dk2_24\0\dk3_24\0\dk4_24\0\dk5_24\0\dk6_24\1\tw0_24\0\tw1_24\0\tw2_24\26\tw3_24\0\tw4_24\18\tw5_24\0\tw6_24\0\tw7_24\0\tw8_24\0\te0_24\0\te1_24\0\te3_24\32\te2_24\0\te4_24\0\te5_24\0\te6_24\0\te7_24\0\te8_24\0\kw0_24\0\kw1_24\0\kw2_24\0\kw3_24\0\kw4_24\0\kw5_24\0\kw6_24\0\kw7_24\0\kw8_24\0\ke0_24\0\ke1_24\0\ke3_24\0\ke2_24\0\ke4_24\0\ke5_24\0\bw0_24\0\bw1_24\0\bw2_24\0\bw3_24\0\bw4_24\0\bw5_24\0\bw6_24\0\bw7_24\0\bw8_24\0\be0_24\0\be1_24\0\be3_24\1\be2_24\0\be4_24\0\be5_24\0\be8_24\0\be9_24\0\de6_24\0\de7_24\0\de8_24\0\sw0_24\0\sw1_24\0\sw2_24\0\sw3_24\0\sw4_24\0\sw5_24\0\sw6_24\0\sw7_24\0\sw8_24\0\se0_24\0\se1_24\0\se2_24\0\se3_24\0\se4_24\0\se5_24\0\hw0_24\0\hw1_24\0\hw2_24\0\hw3_24\0\hw4_24\0\hw5_24\0\hw6_24\0\hw7_24\0\hw8_24\0\he0_24\0\he1_24\0\he2_24\0\he3_24\0\he4_24\0\he5_24\0\pID_25\28999894\name_25\L. Brown\t_25\2\a_25\0\ctime_25\88\c_25\1\ip_25\127.0.0.1\ai_25\1\rs_25\0\cs_25\0\ss_25\0\ts_25\0\kills_25\0\deaths_25\0\cpc_25\0\cpa_25\0\cpd_25\0\ka_25\0\he_25\0\rev_25\0\rsp_25\0\rep_25\0\tre_25\0\drs_25\0\tmkl_25\0\tmdg_25\0\tmvd_25\0\su_25\0\ks_25\0\ds_25\0\rank_25\0\ban_25\0\kck_25\0\tco_25\0\tsl_25\0\tsm_25\88\tlw_25\0\ta0_25\88\ta1_25\0\ta2_25\0\ta3_25\0\ta4_25\0\ta5_25\0\ta6_25\0\ta7_25\0\ta8_25\0\ta9_25\0\ta10_25\0\ta11_25\0\ta12_25\0\ta13_25\0\tv0_25\0\tv1_25\0\tv2_25\0\tv3_25\0\tv4_25\0\tv5_25\0\tv6_25\0\tvp_25\0\kv0_25\0\kv1_25\0\kv2_25\0\kv3_25\0\kv4_25\0\kv5_25\0\kv6_25\0\bv0_25\0\bv1_25\0\bv2_25\0\bv3_25\0\bv4_25\0\bv5_25\0\bv6_25\0\kvr0_25\0\kvr1_25\0\kvr2_25\0\kvr3_25\0\kvr4_25\0\kvr5_25\0\kvr6_25\0\tk0_25\0\tk1_25\88\tk2_25\0\tk3_25\0\tk4_25\0\tk5_25\0\tk6_25\0\kk0_25\0\kk1_25\0\kk2_25\0\kk3_25\0\kk4_25\0\kk5_25\0\kk6_25\0\dk0_25\0\dk1_25\0\dk2_25\0\dk3_25\0\dk4_25\0\dk5_25\0\dk6_25\0\tw0_25\85\tw1_25\2\tw2_25\0\tw3_25\0\tw4_25\0\tw5_25\0\tw6_25\0\tw7_25\0\tw8_25\0\te0_25\0\te1_25\0\te3_25\0\te2_25\0\te4_25\0\te5_25\0\te6_25\0\te7_25\0\te8_25\0\kw0_25\0\kw1_25\0\kw2_25\0\kw3_25\0\kw4_25\0\kw5_25\0\kw6_25\0\kw7_25\0\kw8_25\0\ke0_25\0\ke1_25\0\ke3_25\0\ke2_25\0\ke4_25\0\ke5_25\0\bw0_25\0\bw1_25\0\bw2_25\0\bw3_25\0\bw4_25\0\bw5_25\0\bw6_25\0\bw7_25\0\bw8_25\0\be0_25\0\be1_25\0\be3_25\0\be2_25\0\be4_25\0\be5_25\0\be8_25\0\be9_25\0\de6_25\0\de7_25\0\de8_25\0\sw0_25\30\sw1_25\0\sw2_25\0\sw3_25\0\sw4_25\0\sw5_25\0\sw6_25\0\sw7_25\0\sw8_25\0\se0_25\0\se1_25\0\se2_25\0\se3_25\0\se4_25\0\se5_25\0\hw0_25\1\hw1_25\0\hw2_25\0\hw3_25\0\hw4_25\0\hw5_25\0\hw6_25\0\hw7_25\0\hw8_25\0\he0_25\0\he1_25\0\he2_25\0\he3_25\0\he4_25\0\he5_25\0\pID_26\28999962\name_26\A. Andersson\t_26\2\a_26\0\ctime_26\88\c_26\1\ip_26\127.0.0.1\ai_26\1\rs_26\0\cs_26\0\ss_26\0\ts_26\0\kills_26\0\deaths_26\1\cpc_26\0\cpa_26\0\cpd_26\0\ka_26\0\he_26\0\rev_26\0\rsp_26\0\rep_26\0\tre_26\0\drs_26\0\tmkl_26\0\tmdg_26\0\tmvd_26\0\su_26\0\ks_26\0\ds_26\1\rank_26\0\ban_26\0\kck_26\0\tco_26\0\tsl_26\0\tsm_26\88\tlw_26\0\ta0_26\88\ta1_26\0\ta2_26\0\ta3_26\0\ta4_26\0\ta5_26\0\ta6_26\0\ta7_26\0\ta8_26\0\ta9_26\0\ta10_26\0\ta11_26\0\ta12_26\0\ta13_26\0\tv0_26\0\tv1_26\0\tv2_26\0\tv3_26\0\tv4_26\0\tv5_26\0\tv6_26\0\tvp_26\0\kv0_26\0\kv1_26\0\kv2_26\0\kv3_26\0\kv4_26\0\kv5_26\0\kv6_26\0\bv0_26\0\bv1_26\0\bv2_26\0\bv3_26\0\bv4_26\0\bv5_26\0\bv6_26\0\kvr0_26\0\kvr1_26\0\kvr2_26\0\kvr3_26\0\kvr4_26\0\kvr5_26\0\kvr6_26\0\tk0_26\0\tk1_26\0\tk2_26\0\tk3_26\77\tk4_26\0\tk5_26\0\tk6_26\0\kk0_26\0\kk1_26\0\kk2_26\0\kk3_26\0\kk4_26\0\kk5_26\0\kk6_26\0\dk0_26\0\dk1_26\0\dk2_26\0\dk3_26\1\dk4_26\0\dk5_26\0\dk6_26\0\tw0_26\71\tw1_26\0\tw2_26\0\tw3_26\0\tw4_26\0\tw5_26\0\tw6_26\0\tw7_26\0\tw8_26\0\te0_26\0\te1_26\0\te3_26\4\te2_26\0\te4_26\2\te5_26\0\te6_26\0\te7_26\0\te8_26\0\kw0_26\0\kw1_26\0\kw2_26\0\kw3_26\0\kw4_26\0\kw5_26\0\kw6_26\0\kw7_26\0\kw8_26\0\ke0_26\0\ke1_26\0\ke3_26\0\ke2_26\0\ke4_26\0\ke5_26\0\bw0_26\0\bw1_26\0\bw2_26\0\bw3_26\0\bw4_26\0\bw5_26\0\bw6_26\0\bw7_26\0\bw8_26\0\be0_26\0\be1_26\0\be3_26\1\be2_26\0\be4_26\0\be5_26\0\be8_26\0\be9_26\0\de6_26\0\de7_26\0\de8_26\0\sw0_26\0\sw1_26\0\sw2_26\0\sw3_26\0\sw4_26\0\sw5_26\0\sw6_26\0\sw7_26\0\sw8_26\0\se0_26\0\se1_26\0\se2_26\0\se3_26\0\se4_26\0\se5_26\0\hw0_26\0\hw1_26\0\hw2_26\0\hw3_26\0\hw4_26\0\hw5_26\0\hw6_26\0\hw7_26\0\hw8_26\0\he0_26\0\he1_26\0\he2_26\0\he3_26\0\he4_26\0\he5_26\0\pID_27\28999993\name_27\N. Stromquist\t_27\2\a_27\0\ctime_27\88\c_27\1\ip_27\127.0.0.1\ai_27\1\rs_27\0\cs_27\0\ss_27\0\ts_27\0\kills_27\0\deaths_27\1\cpc_27\0\cpa_27\0\cpd_27\0\ka_27\0\he_27\0\rev_27\0\rsp_27\0\rep_27\0\tre_27\0\drs_27\0\tmkl_27\0\tmdg_27\0\tmvd_27\0\su_27\0\ks_27\0\ds_27\1\rank_27\0\ban_27\0\kck_27\0\tco_27\0\tsl_27\0\tsm_27\88\tlw_27\0\ta0_27\88\ta1_27\0\ta2_27\0\ta3_27\0\ta4_27\0\ta5_27\0\ta6_27\0\ta7_27\0\ta8_27\0\ta9_27\0\ta10_27\0\ta11_27\0\ta12_27\0\ta13_27\0\tv0_27\0\tv1_27\0\tv2_27\0\tv3_27\0\tv4_27\0\tv5_27\0\tv6_27\0\tvp_27\0\kv0_27\0\kv1_27\0\kv2_27\0\kv3_27\0\kv4_27\0\kv5_27\0\kv6_27\0\bv0_27\0\bv1_27\0\bv2_27\0\bv3_27\0\bv4_27\0\bv5_27\0\bv6_27\0\kvr0_27\0\kvr1_27\0\kvr2_27\0\kvr3_27\0\kvr4_27\0\kvr5_27\0\kvr6_27\0\tk0_27\0\tk1_27\54\tk2_27\0\tk3_27\0\tk4_27\0\tk5_27\0\tk6_27\22\kk0_27\0\kk1_27\0\kk2_27\0\kk3_27\0\kk4_27\0\kk5_27\0\kk6_27\0\dk0_27\0\dk1_27\1\dk2_27\0\dk3_27\0\dk4_27\0\dk5_27\0\dk6_27\0\tw0_27\39\tw1_27\14\tw2_27\0\tw3_27\0\tw4_27\9\tw5_27\0\tw6_27\0\tw7_27\0\tw8_27\0\te0_27\0\te1_27\0\te3_27\12\te2_27\0\te4_27\0\te5_27\0\te6_27\0\te7_27\0\te8_27\0\kw0_27\0\kw1_27\0\kw2_27\0\kw3_27\0\kw4_27\0\kw5_27\0\kw6_27\0\kw7_27\0\kw8_27\0\ke0_27\0\ke1_27\0\ke3_27\0\ke2_27\0\ke4_27\0\ke5_27\0\bw0_27\0\bw1_27\1\bw2_27\0\bw3_27\0\bw4_27\0\bw5_27\0\bw6_27\0\bw7_27\0\bw8_27\0\be0_27\0\be1_27\0\be3_27\0\be2_27\0\be4_27\0\be5_27\0\be8_27\0\be9_27\0\de6_27\0\de7_27\0\de8_27\0\sw0_27\0\sw1_27\1\sw2_27\0\sw3_27\0\sw4_27\2\sw5_27\0\sw6_27\0\sw7_27\0\sw8_27\0\se0_27\0\se1_27\0\se2_27\0\se3_27\0\se4_27\0\se5_27\0\hw0_27\0\hw1_27\0\hw2_27\0\hw3_27\0\hw4_27\0\hw5_27\0\hw6_27\0\hw7_27\0\hw8_27\0\he0_27\0\he1_27\0\he2_27\0\he3_27\0\he4_27\0\he5_27\0\pID_28\28999972\name_28\J. Hargelid\t_28\2\a_28\0\ctime_28\88\c_28\1\ip_28\127.0.0.1\ai_28\1\rs_28\2\cs_28\0\ss_28\2\ts_28\0\kills_28\1\deaths_28\1\cpc_28\0\cpa_28\0\cpd_28\0\ka_28\0\he_28\0\rev_28\0\rsp_28\0\rep_28\0\tre_28\0\drs_28\0\tmkl_28\0\tmdg_28\0\tmvd_28\0\su_28\0\ks_28\1\ds_28\1\rank_28\0\ban_28\0\kck_28\0\tco_28\0\tsl_28\0\tsm_28\88\tlw_28\0\ta0_28\88\ta1_28\0\ta2_28\0\ta3_28\0\ta4_28\0\ta5_28\0\ta6_28\0\ta7_28\0\ta8_28\0\ta9_28\0\ta10_28\0\ta11_28\0\ta12_28\0\ta13_28\0\mvns_28\28999971\mvks_28\1\tv0_28\0\tv1_28\0\tv2_28\0\tv3_28\0\tv4_28\8\tv5_28\0\tv6_28\0\tvp_28\0\kv0_28\0\kv1_28\0\kv2_28\0\kv3_28\0\kv4_28\1\kv5_28\0\kv6_28\0\bv0_28\0\bv1_28\0\bv2_28\0\bv3_28\0\bv4_28\0\bv5_28\0\bv6_28\0\kvr0_28\0\kvr1_28\0\kvr2_28\0\kvr3_28\0\kvr4_28\0\kvr5_28\0\kvr6_28\0\tk0_28\61\tk1_28\0\tk2_28\0\tk3_28\0\tk4_28\0\tk5_28\0\tk6_28\16\kk0_28\0\kk1_28\0\kk2_28\0\kk3_28\0\kk4_28\0\kk5_28\0\kk6_28\1\dk0_28\1\dk1_28\0\dk2_28\0\dk3_28\0\dk4_28\0\dk5_28\0\dk6_28\0\tw0_28\0\tw1_28\0\tw2_28\0\tw3_28\0\tw4_28\7\tw5_28\0\tw6_28\6\tw7_28\54\tw8_28\0\te0_28\0\te1_28\0\te3_28\0\te2_28\0\te4_28\0\te5_28\0\te6_28\0\te7_28\0\te8_28\0\kw0_28\0\kw1_28\0\kw2_28\0\kw3_28\0\kw4_28\0\kw5_28\0\kw6_28\0\kw7_28\0\kw8_28\0\ke0_28\0\ke1_28\0\ke3_28\0\ke2_28\0\ke4_28\0\ke5_28\0\bw0_28\0\bw1_28\0\bw2_28\0\bw3_28\0\bw4_28\0\bw5_28\0\bw6_28\0\bw7_28\1\bw8_28\0\be0_28\0\be1_28\0\be3_28\0\be2_28\0\be4_28\0\be5_28\0\be8_28\0\be9_28\0\de6_28\0\de7_28\0\de8_28\0\sw0_28\0\sw1_28\0\sw2_28\0\sw3_28\0\sw4_28\0\sw5_28\0\sw6_28\1\sw7_28\0\sw8_28\0\se0_28\0\se1_28\0\se2_28\0\se3_28\0\se4_28\0\se5_28\0\hw0_28\0\hw1_28\0\hw2_28\0\hw3_28\0\hw4_28\0\hw5_28\0\hw6_28\0\hw7_28\0\hw8_28\0\he0_28\0\he1_28\0\he2_28\0\he3_28\0\he4_28\0\he5_28\0\pID_29\28999888\name_29\P. OShaughnessy\t_29\2\a_29\0\ctime_29\88\c_29\1\ip_29\127.0.0.1\ai_29\1\rs_29\2\cs_29\0\ss_29\2\ts_29\0\kills_29\1\deaths_29\0\cpc_29\0\cpa_29\0\cpd_29\0\ka_29\0\he_29\0\rev_29\0\rsp_29\0\rep_29\0\tre_29\0\drs_29\0\tmkl_29\0\tmdg_29\0\tmvd_29\0\su_29\0\ks_29\1\ds_29\0\rank_29\0\ban_29\0\kck_29\0\tco_29\0\tsl_29\88\tsm_29\0\tlw_29\0\ta0_29\88\ta1_29\0\ta2_29\0\ta3_29\0\ta4_29\0\ta5_29\0\ta6_29\0\ta7_29\0\ta8_29\0\ta9_29\0\ta10_29\0\ta11_29\0\ta12_29\0\ta13_29\0\mvns_29\28999938\mvks_29\1\tv0_29\0\tv1_29\0\tv2_29\0\tv3_29\0\tv4_29\0\tv5_29\0\tv6_29\0\tvp_29\0\kv0_29\0\kv1_29\0\kv2_29\0\kv3_29\0\kv4_29\0\kv5_29\0\kv6_29\0\bv0_29\0\bv1_29\0\bv2_29\0\bv3_29\0\bv4_29\0\bv5_29\0\bv6_29\0\kvr0_29\0\kvr1_29\0\kvr2_29\0\kvr3_29\0\kvr4_29\0\kvr5_29\0\kvr6_29\0\tk0_29\0\tk1_29\0\tk2_29\0\tk3_29\0\tk4_29\88\tk5_29\0\tk6_29\0\kk0_29\0\kk1_29\0\kk2_29\0\kk3_29\0\kk4_29\1\kk5_29\0\kk6_29\0\dk0_29\0\dk1_29\0\dk2_29\0\dk3_29\0\dk4_29\0\dk5_29\0\dk6_29\0\tw0_29\0\tw1_29\0\tw2_29\78\tw3_29\0\tw4_29\0\tw5_29\0\tw6_29\0\tw7_29\0\tw8_29\0\te0_29\0\te1_29\6\te3_29\3\te2_29\0\te4_29\0\te5_29\0\te6_29\0\te7_29\0\te8_29\0\kw0_29\0\kw1_29\0\kw2_29\1\kw3_29\0\kw4_29\0\kw5_29\0\kw6_29\0\kw7_29\0\kw8_29\0\ke0_29\0\ke1_29\0\ke3_29\0\ke2_29\0\ke4_29\0\ke5_29\0\bw0_29\0\bw1_29\0\bw2_29\0\bw3_29\0\bw4_29\0\bw5_29\0\bw6_29\0\bw7_29\0\bw8_29\0\be0_29\0\be1_29\0\be3_29\0\be2_29\0\be4_29\0\be5_29\0\be8_29\0\be9_29\0\de6_29\0\de7_29\0\de8_29\0\sw0_29\0\sw1_29\0\sw2_29\29\sw3_29\0\sw4_29\0\sw5_29\0\sw6_29\0\sw7_29\0\sw8_29\0\se0_29\0\se1_29\0\se2_29\0\se3_29\1\se4_29\0\se5_29\0\hw0_29\0\hw1_29\0\hw2_29\4\hw3_29\0\hw4_29\0\hw5_29\0\hw6_29\0\hw7_29\0\hw8_29\0\he0_29\0\he1_29\0\he2_29\0\he3_29\0\he4_29\0\he5_29\0\pID_30\28999922\name_30\R. Lopez\t_30\2\a_30\0\ctime_30\88\c_30\1\ip_30\127.0.0.1\ai_30\1\rs_30\0\cs_30\0\ss_30\0\ts_30\0\kills_30\0\deaths_30\0\cpc_30\0\cpa_30\0\cpd_30\0\ka_30\0\he_30\0\rev_30\0\rsp_30\0\rep_30\0\tre_30\0\drs_30\0\tmkl_30\0\tmdg_30\0\tmvd_30\0\su_30\0\ks_30\0\ds_30\0\rank_30\0\ban_30\0\kck_30\0\tco_30\0\tsl_30\0\tsm_30\88\tlw_30\0\ta0_30\88\ta1_30\0\ta2_30\0\ta3_30\0\ta4_30\0\ta5_30\0\ta6_30\0\ta7_30\0\ta8_30\0\ta9_30\0\ta10_30\0\ta11_30\0\ta12_30\0\ta13_30\0\tv0_30\0\tv1_30\0\tv2_30\0\tv3_30\0\tv4_30\0\tv5_30\0\tv6_30\0\tvp_30\0\kv0_30\0\kv1_30\0\kv2_30\0\kv3_30\0\kv4_30\0\kv5_30\0\kv6_30\0\bv0_30\0\bv1_30\0\bv2_30\0\bv3_30\0\bv4_30\0\bv5_30\0\bv6_30\0\kvr0_30\0\kvr1_30\0\kvr2_30\0\kvr3_30\0\kvr4_30\0\kvr5_30\0\kvr6_30\0\tk0_30\0\tk1_30\0\tk2_30\0\tk3_30\0\tk4_30\88\tk5_30\0\tk6_30\0\kk0_30\0\kk1_30\0\kk2_30\0\kk3_30\0\kk4_30\0\kk5_30\0\kk6_30\0\dk0_30\0\dk1_30\0\dk2_30\0\dk3_30\0\dk4_30\0\dk5_30\0\dk6_30\0\tw0_30\0\tw1_30\0\tw2_30\86\tw3_30\0\tw4_30\0\tw5_30\0\tw6_30\0\tw7_30\0\tw8_30\0\te0_30\0\te1_30\1\te3_30\0\te2_30\0\te4_30\0\te5_30\0\te6_30\0\te7_30\0\te8_30\0\kw0_30\0\kw1_30\0\kw2_30\0\kw3_30\0\kw4_30\0\kw5_30\0\kw6_30\0\kw7_30\0\kw8_30\0\ke0_30\0\ke1_30\0\ke3_30\0\ke2_30\0\ke4_30\0\ke5_30\0\bw0_30\0\bw1_30\0\bw2_30\0\bw3_30\0\bw4_30\0\bw5_30\0\bw6_30\0\bw7_30\0\bw8_30\0\be0_30\0\be1_30\0\be3_30\0\be2_30\0\be4_30\0\be5_30\0\be8_30\0\be9_30\0\de6_30\0\de7_30\0\de8_30\0\sw0_30\0\sw1_30\0\sw2_30\22\sw3_30\0\sw4_30\0\sw5_30\0\sw6_30\0\sw7_30\0\sw8_30\0\se0_30\0\se1_30\1\se2_30\0\se3_30\0\se4_30\0\se5_30\0\hw0_30\0\hw1_30\0\hw2_30\0\hw3_30\0\hw4_30\0\hw5_30\0\hw6_30\0\hw7_30\0\hw8_30\0\he0_30\0\he1_30\0\he2_30\0\he3_30\0\he4_30\0\he5_30\0\pID_31\28999946\name_31\M. Hedlund\t_31\2\a_31\0\ctime_31\73\c_31\1\ip_31\127.0.0.1\ai_31\1\rs_31\0\cs_31\0\ss_31\0\ts_31\0\kills_31\0\deaths_31\1\cpc_31\0\cpa_31\0\cpd_31\0\ka_31\0\he_31\0\rev_31\0\rsp_31\0\rep_31\0\tre_31\0\drs_31\1\tmkl_31\2\tmdg_31\1\tmvd_31\0\su_31\0\ks_31\0\ds_31\1\rank_31\0\ban_31\0\kck_31\0\tco_31\0\tsl_31\0\tsm_31\73\tlw_31\0\ta0_31\73\ta1_31\0\ta2_31\0\ta3_31\0\ta4_31\0\ta5_31\0\ta6_31\0\ta7_31\0\ta8_31\0\ta9_31\0\ta10_31\0\ta11_31\0\ta12_31\0\ta13_31\0\tv0_31\64\tv1_31\0\tv2_31\0\tv3_31\0\tv4_31\0\tv5_31\0\tv6_31\0\tvp_31\0\kv0_31\0\kv1_31\0\kv2_31\0\kv3_31\0\kv4_31\0\kv5_31\0\kv6_31\0\bv0_31\1\bv1_31\0\bv2_31\0\bv3_31\0\bv4_31\0\bv5_31\0\bv6_31\0\kvr0_31\0\kvr1_31\0\kvr2_31\0\kvr3_31\0\kvr4_31\0\kvr5_31\0\kvr6_31\0\tk0_31\0\tk1_31\0\tk2_31\0\tk3_31\73\tk4_31\0\tk5_31\0\tk6_31\0\kk0_31\0\kk1_31\0\kk2_31\0\kk3_31\0\kk4_31\0\kk5_31\0\kk6_31\0\dk0_31\0\dk1_31\0\dk2_31\0\dk3_31\1\dk4_31\0\dk5_31\0\dk6_31\0\tw0_31\9\tw1_31\0\tw2_31\0\tw3_31\0\tw4_31\0\tw5_31\0\tw6_31\0\tw7_31\0\tw8_31\0\te0_31\0\te1_31\0\te3_31\0\te2_31\0\te4_31\0\te5_31\0\te6_31\0\te7_31\0\te8_31\0\kw0_31\0\kw1_31\0\kw2_31\0\kw3_31\0\kw4_31\0\kw5_31\0\kw6_31\0\kw7_31\0\kw8_31\0\ke0_31\0\ke1_31\0\ke3_31\0\ke2_31\0\ke4_31\0\ke5_31\0\bw0_31\0\bw1_31\0\bw2_31\0\bw3_31\0\bw4_31\0\bw5_31\0\bw6_31\0\bw7_31\0\bw8_31\0\be0_31\0\be1_31\0\be3_31\0\be2_31\0\be4_31\0\be5_31\0\be8_31\0\be9_31\0\de6_31\0\de7_31\0\de8_31\0\sw0_31\0\sw1_31\0\sw2_31\0\sw3_31\0\sw4_31\0\sw5_31\0\sw6_31\0\sw7_31\0\sw8_31\0\se0_31\0\se1_31\0\se2_31\0\se3_31\0\se4_31\0\se5_31\0\hw0_31\0\hw1_31\0\hw2_31\0\hw3_31\0\hw4_31\0\hw5_31\0\hw6_31\0\hw7_31\0\hw8_31\0\he0_31\0\he1_31\0\he2_31\0\he3_31\0\he4_31\0\he5_31\0\pID_32\28999986\name_32\D. Votypka\t_32\2\a_32\0\ctime_32\88\c_32\1\ip_32\127.0.0.1\ai_32\1\rs_32\0\cs_32\0\ss_32\0\ts_32\0\kills_32\0\deaths_32\0\cpc_32\0\cpa_32\0\cpd_32\0\ka_32\0\he_32\0\rev_32\0\rsp_32\0\rep_32\0\tre_32\0\drs_32\0\tmkl_32\0\tmdg_32\0\tmvd_32\0\su_32\0\ks_32\0\ds_32\0\rank_32\0\ban_32\0\kck_32\0\tco_32\0\tsl_32\0\tsm_32\88\tlw_32\0\ta0_32\88\ta1_32\0\ta2_32\0\ta3_32\0\ta4_32\0\ta5_32\0\ta6_32\0\ta7_32\0\ta8_32\0\ta9_32\0\ta10_32\0\ta11_32\0\ta12_32\0\ta13_32\0\tv0_32\0\tv1_32\0\tv2_32\0\tv3_32\0\tv4_32\0\tv5_32\0\tv6_32\0\tvp_32\0\kv0_32\0\kv1_32\0\kv2_32\0\kv3_32\0\kv4_32\0\kv5_32\0\kv6_32\0\bv0_32\0\bv1_32\0\bv2_32\0\bv3_32\0\bv4_32\0\bv5_32\0\bv6_32\0\kvr0_32\0\kvr1_32\0\kvr2_32\0\kvr3_32\0\kvr4_32\0\kvr5_32\0\kvr6_32\0\tk0_32\88\tk1_32\0\tk2_32\0\tk3_32\0\tk4_32\0\tk5_32\0\tk6_32\0\kk0_32\0\kk1_32\0\kk2_32\0\kk3_32\0\kk4_32\0\kk5_32\0\kk6_32\0\dk0_32\0\dk1_32\0\dk2_32\0\dk3_32\0\dk4_32\0\dk5_32\0\dk6_32\0\tw0_32\0\tw1_32\0\tw2_32\0\tw3_32\0\tw4_32\0\tw5_32\4\tw6_32\4\tw7_32\79\tw8_32\0\te0_32\0\te1_32\0\te3_32\0\te2_32\0\te4_32\0\te5_32\0\te6_32\0\te7_32\0\te8_32\0\kw0_32\0\kw1_32\0\kw2_32\0\kw3_32\0\kw4_32\0\kw5_32\0\kw6_32\0\kw7_32\0\kw8_32\0\ke0_32\0\ke1_32\0\ke3_32\0\ke2_32\0\ke4_32\0\ke5_32\0\bw0_32\0\bw1_32\0\bw2_32\0\bw3_32\0\bw4_32\0\bw5_32\0\bw6_32\0\bw7_32\0\bw8_32\0\be0_32\0\be1_32\0\be3_32\0\be2_32\0\be4_32\0\be5_32\0\be8_32\0\be9_32\0\de6_32\0\de7_32\0\de8_32\0\sw0_32\0\sw1_32\0\sw2_32\0\sw3_32\0\sw4_32\0\sw5_32\15\sw6_32\1\sw7_32\30\sw8_32\0\se0_32\0\se1_32\0\se2_32\0\se3_32\0\se4_32\0\se5_32\0\hw0_32\0\hw1_32\0\hw2_32\0\hw3_32\0\hw4_32\0\hw5_32\0\hw6_32\1\hw7_32\0\hw8_32\0\he0_32\0\he1_32\0\he2_32\0\he3_32\0\he4_32\0\he5_32\0\pID_33\28999890\name_33\P. Osterblom\t_33\2\a_33\0\ctime_33\88\c_33\1\ip_33\127.0.0.1\ai_33\1\rs_33\2\cs_33\0\ss_33\2\ts_33\0\kills_33\1\deaths_33\0\cpc_33\0\cpa_33\0\cpd_33\0\ka_33\0\he_33\0\rev_33\0\rsp_33\0\rep_33\0\tre_33\0\drs_33\0\tmkl_33\0\tmdg_33\0\tmvd_33\0\su_33\0\ks_33\1\ds_33\0\rank_33\0\ban_33\0\kck_33\0\tco_33\0\tsl_33\0\tsm_33\88\tlw_33\0\ta0_33\88\ta1_33\0\ta2_33\0\ta3_33\0\ta4_33\0\ta5_33\0\ta6_33\0\ta7_33\0\ta8_33\0\ta9_33\0\ta10_33\0\ta11_33\0\ta12_33\0\ta13_33\0\mvns_33\28999901\mvks_33\1\tv0_33\0\tv1_33\0\tv2_33\0\tv3_33\0\tv4_33\0\tv5_33\0\tv6_33\0\tvp_33\0\kv0_33\0\kv1_33\0\kv2_33\0\kv3_33\0\kv4_33\0\kv5_33\0\kv6_33\0\bv0_33\0\bv1_33\0\bv2_33\0\bv3_33\0\bv4_33\0\bv5_33\0\bv6_33\0\kvr0_33\0\kvr1_33\0\kvr2_33\0\kvr3_33\0\kvr4_33\0\kvr5_33\0\kvr6_33\0\tk0_33\0\tk1_33\0\tk2_33\0\tk3_33\0\tk4_33\88\tk5_33\0\tk6_33\0\kk0_33\0\kk1_33\0\kk2_33\0\kk3_33\0\kk4_33\1\kk5_33\0\kk6_33\0\dk0_33\0\dk1_33\0\dk2_33\0\dk3_33\0\dk4_33\0\dk5_33\0\dk6_33\0\tw0_33\0\tw1_33\0\tw2_33\80\tw3_33\0\tw4_33\0\tw5_33\0\tw6_33\0\tw7_33\0\tw8_33\0\te0_33\0\te1_33\7\te3_33\1\te2_33\0\te4_33\0\te5_33\0\te6_33\0\te7_33\0\te8_33\0\kw0_33\0\kw1_33\0\kw2_33\1\kw3_33\0\kw4_33\0\kw5_33\0\kw6_33\0\kw7_33\0\kw8_33\0\ke0_33\0\ke1_33\0\ke3_33\0\ke2_33\0\ke4_33\0\ke5_33\0\bw0_33\0\bw1_33\0\bw2_33\0\bw3_33\0\bw4_33\0\bw5_33\0\bw6_33\0\bw7_33\0\bw8_33\0\be0_33\0\be1_33\0\be3_33\0\be2_33\0\be4_33\0\be5_33\0\be8_33\0\be9_33\0\de6_33\0\de7_33\0\de8_33\0\sw0_33\0\sw1_33\0\sw2_33\21\sw3_33\0\sw4_33\0\sw5_33\0\sw6_33\0\sw7_33\0\sw8_33\0\se0_33\0\se1_33\0\se2_33\0\se3_33\0\se4_33\0\se5_33\0\hw0_33\0\hw1_33\0\hw2_33\1\hw3_33\0\hw4_33\0\hw5_33\0\hw6_33\0\hw7_33\0\hw8_33\0\he0_33\0\he1_33\0\he2_33\0\he3_33\0\he4_33\0\he5_33\0\pID_34\28999893\name_34\S. Strandberg\t_34\2\a_34\0\ctime_34\88\c_34\1\ip_34\127.0.0.1\ai_34\1\rs_34\0\cs_34\0\ss_34\0\ts_34\0\kills_34\0\deaths_34\1\cpc_34\0\cpa_34\0\cpd_34\0\ka_34\0\he_34\0\rev_34\0\rsp_34\0\rep_34\0\tre_34\0\drs_34\0\tmkl_34\0\tmdg_34\0\tmvd_34\0\su_34\0\ks_34\0\ds_34\1\rank_34\0\ban_34\0\kck_34\0\tco_34\0\tsl_34\88\tsm_34\0\tlw_34\0\ta0_34\88\ta1_34\0\ta2_34\0\ta3_34\0\ta4_34\0\ta5_34\0\ta6_34\0\ta7_34\0\ta8_34\0\ta9_34\0\ta10_34\0\ta11_34\0\ta12_34\0\ta13_34\0\tv0_34\0\tv1_34\0\tv2_34\0\tv3_34\0\tv4_34\0\tv5_34\0\tv6_34\0\tvp_34\0\kv0_34\0\kv1_34\0\kv2_34\0\kv3_34\0\kv4_34\0\kv5_34\0\kv6_34\0\bv0_34\0\bv1_34\0\bv2_34\0\bv3_34\0\bv4_34\0\bv5_34\0\bv6_34\0\kvr0_34\0\kvr1_34\0\kvr2_34\0\kvr3_34\0\kvr4_34\0\kvr5_34\0\kvr6_34\0\tk0_34\0\tk1_34\42\tk2_34\0\tk3_34\0\tk4_34\34\tk5_34\0\tk6_34\0\kk0_34\0\kk1_34\0\kk2_34\0\kk3_34\0\kk4_34\0\kk5_34\0\kk6_34\0\dk0_34\0\dk1_34\0\dk2_34\0\dk3_34\0\dk4_34\1\dk5_34\0\dk6_34\0\tw0_34\42\tw1_34\0\tw2_34\24\tw3_34\0\tw4_34\0\tw5_34\0\tw6_34\0\tw7_34\0\tw8_34\0\te0_34\0\te1_34\10\te3_34\0\te2_34\0\te4_34\0\te5_34\0\te6_34\0\te7_34\0\te8_34\0\kw0_34\0\kw1_34\0\kw2_34\0\kw3_34\0\kw4_34\0\kw5_34\0\kw6_34\0\kw7_34\0\kw8_34\0\ke0_34\0\ke1_34\0\ke3_34\0\ke2_34\0\ke4_34\0\ke5_34\0\bw0_34\0\bw1_34\0\bw2_34\0\bw3_34\0\bw4_34\0\bw5_34\0\bw6_34\0\bw7_34\0\bw8_34\0\be0_34\0\be1_34\1\be3_34\0\be2_34\0\be4_34\0\be5_34\0\be8_34\0\be9_34\0\de6_34\0\de7_34\0\de8_34\0\sw0_34\0\sw1_34\0\sw2_34\0\sw3_34\0\sw4_34\0\sw5_34\0\sw6_34\0\sw7_34\0\sw8_34\0\se0_34\0\se1_34\0\se2_34\0\se3_34\0\se4_34\0\se5_34\0\hw0_34\0\hw1_34\0\hw2_34\0\hw3_34\0\hw4_34\0\hw5_34\0\hw6_34\0\hw7_34\0\hw8_34\0\he0_34\0\he1_34\0\he2_34\0\he3_34\0\he4_34\0\he5_34\0\pID_35\28999950\name_35\J. Aberg\t_35\2\a_35\0\ctime_35\88\c_35\1\ip_35\127.0.0.1\ai_35\1\rs_35\0\cs_35\0\ss_35\0\ts_35\0\kills_35\0\deaths_35\1\cpc_35\0\cpa_35\0\cpd_35\0\ka_35\0\he_35\0\rev_35\0\rsp_35\0\rep_35\0\tre_35\0\drs_35\0\tmkl_35\0\tmdg_35\0\tmvd_35\0\su_35\0\ks_35\0\ds_35\1\rank_35\0\ban_35\0\kck_35\0\tco_35\0\tsl_35\0\tsm_35\88\tlw_35\0\ta0_35\88\ta1_35\0\ta2_35\0\ta3_35\0\ta4_35\0\ta5_35\0\ta6_35\0\ta7_35\0\ta8_35\0\ta9_35\0\ta10_35\0\ta11_35\0\ta12_35\0\ta13_35\0\tv0_35\0\tv1_35\0\tv2_35\0\tv3_35\0\tv4_35\0\tv5_35\0\tv6_35\0\tvp_35\0\kv0_35\0\kv1_35\0\kv2_35\0\kv3_35\0\kv4_35\0\kv5_35\0\kv6_35\0\bv0_35\0\bv1_35\0\bv2_35\0\bv3_35\0\bv4_35\0\bv5_35\0\bv6_35\0\kvr0_35\0\kvr1_35\0\kvr2_35\0\kvr3_35\0\kvr4_35\0\kvr5_35\0\kvr6_35\0\tk0_35\0\tk1_35\0\tk2_35\0\tk3_35\0\tk4_35\0\tk5_35\50\tk6_35\26\kk0_35\0\kk1_35\0\kk2_35\0\kk3_35\0\kk4_35\0\kk5_35\0\kk6_35\0\dk0_35\0\dk1_35\0\dk2_35\0\dk3_35\0\dk4_35\0\dk5_35\1\dk6_35\0\tw0_35\0\tw1_35\0\tw2_35\0\tw3_35\40\tw4_35\26\tw5_35\0\tw6_35\0\tw7_35\0\tw8_35\0\te0_35\0\te1_35\0\te3_35\10\te2_35\0\te4_35\0\te5_35\0\te6_35\0\te7_35\0\te8_35\0\kw0_35\0\kw1_35\0\kw2_35\0\kw3_35\0\kw4_35\0\kw5_35\0\kw6_35\0\kw7_35\0\kw8_35\0\ke0_35\0\ke1_35\0\ke3_35\0\ke2_35\0\ke4_35\0\ke5_35\0\bw0_35\0\bw1_35\0\bw2_35\0\bw3_35\0\bw4_35\0\bw5_35\0\bw6_35\0\bw7_35\0\bw8_35\0\be0_35\0\be1_35\0\be3_35\1\be2_35\0\be4_35\0\be5_35\0\be8_35\0\be9_35\0\de6_35\0\de7_35\0\de8_35\0\sw0_35\0\sw1_35\0\sw2_35\0\sw3_35\0\sw4_35\0\sw5_35\0\sw6_35\0\sw7_35\0\sw8_35\0\se0_35\0\se1_35\0\se2_35\0\se3_35\0\se4_35\0\se5_35\0\hw0_35\0\hw1_35\0\hw2_35\0\hw3_35\0\hw4_35\0\hw5_35\0\hw6_35\0\hw7_35\0\hw8_35\0\he0_35\0\he1_35\0\he2_35\0\he3_35\0\he4_35\0\he5_35\0\pID_36\28999924\name_36\D. Sirland\t_36\2\a_36\0\ctime_36\87\c_36\1\ip_36\127.0.0.1\ai_36\1\rs_36\0\cs_36\0\ss_36\0\ts_36\0\kills_36\0\deaths_36\1\cpc_36\0\cpa_36\0\cpd_36\0\ka_36\0\he_36\0\rev_36\0\rsp_36\0\rep_36\0\tre_36\0\drs_36\0\tmkl_36\0\tmdg_36\0\tmvd_36\0\su_36\0\ks_36\0\ds_36\1\rank_36\0\ban_36\0\kck_36\0\tco_36\0\tsl_36\0\tsm_36\87\tlw_36\0\ta0_36\87\ta1_36\0\ta2_36\0\ta3_36\0\ta4_36\0\ta5_36\0\ta6_36\0\ta7_36\0\ta8_36\0\ta9_36\0\ta10_36\0\ta11_36\0\ta12_36\0\ta13_36\0\tv0_36\0\tv1_36\0\tv2_36\0\tv3_36\0\tv4_36\0\tv5_36\0\tv6_36\0\tvp_36\0\kv0_36\0\kv1_36\0\kv2_36\0\kv3_36\0\kv4_36\0\kv5_36\0\kv6_36\0\bv0_36\0\bv1_36\0\bv2_36\0\bv3_36\0\bv4_36\0\bv5_36\0\bv6_36\0\kvr0_36\0\kvr1_36\0\kvr2_36\0\kvr3_36\0\kvr4_36\0\kvr5_36\0\kvr6_36\0\tk0_36\0\tk1_36\0\tk2_36\0\tk3_36\76\tk4_36\0\tk5_36\0\tk6_36\0\kk0_36\0\kk1_36\0\kk2_36\0\kk3_36\0\kk4_36\0\kk5_36\0\kk6_36\0\dk0_36\0\dk1_36\0\dk2_36\0\dk3_36\1\dk4_36\0\dk5_36\0\dk6_36\0\tw0_36\65\tw1_36\0\tw2_36\0\tw3_36\0\tw4_36\0\tw5_36\0\tw6_36\0\tw7_36\0\tw8_36\0\te0_36\0\te1_36\0\te3_36\9\te2_36\0\te4_36\0\te5_36\0\te6_36\0\te7_36\0\te8_36\0\kw0_36\0\kw1_36\0\kw2_36\0\kw3_36\0\kw4_36\0\kw5_36\0\kw6_36\0\kw7_36\0\kw8_36\0\ke0_36\0\ke1_36\0\ke3_36\0\ke2_36\0\ke4_36\0\ke5_36\0\bw0_36\0\bw1_36\0\bw2_36\0\bw3_36\0\bw4_36\0\bw5_36\0\bw6_36\0\bw7_36\0\bw8_36\0\be0_36\0\be1_36\0\be3_36\1\be2_36\0\be4_36\0\be5_36\0\be8_36\0\be9_36\0\de6_36\0\de7_36\0\de8_36\0\sw0_36\0\sw1_36\0\sw2_36\0\sw3_36\0\sw4_36\0\sw5_36\0\sw6_36\0\sw7_36\0\sw8_36\0\se0_36\0\se1_36\0\se2_36\0\se3_36\0\se4_36\0\se5_36\0\hw0_36\0\hw1_36\0\hw2_36\0\hw3_36\0\hw4_36\0\hw5_36\0\hw6_36\0\hw7_36\0\hw8_36\0\he0_36\0\he1_36\0\he2_36\0\he3_36\0\he4_36\0\he5_36\0\pID_37\28999931\name_37\S. Evans\t_37\2\a_37\0\ctime_37\87\c_37\1\ip_37\127.0.0.1\ai_37\1\rs_37\0\cs_37\0\ss_37\0\ts_37\0\kills_37\0\deaths_37\2\cpc_37\0\cpa_37\0\cpd_37\0\ka_37\0\he_37\0\rev_37\0\rsp_37\0\rep_37\0\tre_37\0\drs_37\0\tmkl_37\0\tmdg_37\0\tmvd_37\0\su_37\0\ks_37\0\ds_37\2\rank_37\0\ban_37\0\kck_37\0\tco_37\0\tsl_37\0\tsm_37\87\tlw_37\0\ta0_37\87\ta1_37\0\ta2_37\0\ta3_37\0\ta4_37\0\ta5_37\0\ta6_37\0\ta7_37\0\ta8_37\0\ta9_37\0\ta10_37\0\ta11_37\0\ta12_37\0\ta13_37\0\tv0_37\0\tv1_37\0\tv2_37\0\tv3_37\0\tv4_37\12\tv5_37\0\tv6_37\0\tvp_37\0\kv0_37\0\kv1_37\0\kv2_37\0\kv3_37\0\kv4_37\0\kv5_37\0\kv6_37\0\bv0_37\0\bv1_37\0\bv2_37\0\bv3_37\0\bv4_37\0\bv5_37\0\bv6_37\0\kvr0_37\0\kvr1_37\0\kvr2_37\0\kvr3_37\0\kvr4_37\0\kvr5_37\0\kvr6_37\0\tk0_37\0\tk1_37\8\tk2_37\0\tk3_37\0\tk4_37\0\tk5_37\38\tk6_37\19\kk0_37\0\kk1_37\0\kk2_37\0\kk3_37\0\kk4_37\0\kk5_37\0\kk6_37\0\dk0_37\0\dk1_37\1\dk2_37\0\dk3_37\0\dk4_37\0\dk5_37\0\dk6_37\1\tw0_37\0\tw1_37\7\tw2_37\0\tw3_37\38\tw4_37\2\tw5_37\0\tw6_37\0\tw7_37\0\tw8_37\0\te0_37\0\te1_37\0\te3_37\4\te2_37\0\te4_37\0\te5_37\0\te6_37\0\te7_37\0\te8_37\0\kw0_37\0\kw1_37\0\kw2_37\0\kw3_37\0\kw4_37\0\kw5_37\0\kw6_37\0\kw7_37\0\kw8_37\0\ke0_37\0\ke1_37\0\ke3_37\0\ke2_37\0\ke4_37\0\ke5_37\0\bw0_37\0\bw1_37\1\bw2_37\0\bw3_37\0\bw4_37\0\bw5_37\0\bw6_37\0\bw7_37\0\bw8_37\0\be0_37\0\be1_37\0\be3_37\1\be2_37\0\be4_37\0\be5_37\0\be8_37\0\be9_37\0\de6_37\0\de7_37\0\de8_37\0\sw0_37\0\sw1_37\1\sw2_37\0\sw3_37\3\sw4_37\0\sw5_37\0\sw6_37\0\sw7_37\0\sw8_37\0\se0_37\0\se1_37\0\se2_37\0\se3_37\0\se4_37\0\se5_37\0\hw0_37\0\hw1_37\0\hw2_37\0\hw3_37\0\hw4_37\0\hw5_37\0\hw6_37\0\hw7_37\0\hw8_37\0\he0_37\0\he1_37\0\he2_37\0\he3_37\0\he4_37\0\he5_37\0\pID_38\28999882\name_38\D. Kerr\t_38\2\a_38\0\ctime_38\88\c_38\1\ip_38\127.0.0.1\ai_38\1\rs_38\0\cs_38\0\ss_38\0\ts_38\0\kills_38\0\deaths_38\0\cpc_38\0\cpa_38\0\cpd_38\0\ka_38\0\he_38\0\rev_38\0\rsp_38\0\rep_38\0\tre_38\0\drs_38\0\tmkl_38\0\tmdg_38\0\tmvd_38\0\su_38\0\ks_38\0\ds_38\0\rank_38\0\ban_38\0\kck_38\0\tco_38\0\tsl_38\0\tsm_38\88\tlw_38\0\ta0_38\88\ta1_38\0\ta2_38\0\ta3_38\0\ta4_38\0\ta5_38\0\ta6_38\0\ta7_38\0\ta8_38\0\ta9_38\0\ta10_38\0\ta11_38\0\ta12_38\0\ta13_38\0\tv0_38\0\tv1_38\0\tv2_38\0\tv3_38\0\tv4_38\0\tv5_38\0\tv6_38\0\tvp_38\0\kv0_38\0\kv1_38\0\kv2_38\0\kv3_38\0\kv4_38\0\kv5_38\0\kv6_38\0\bv0_38\0\bv1_38\0\bv2_38\0\bv3_38\0\bv4_38\0\bv5_38\0\bv6_38\0\kvr0_38\0\kvr1_38\0\kvr2_38\0\kvr3_38\0\kvr4_38\0\kvr5_38\0\kvr6_38\0\tk0_38\0\tk1_38\0\tk2_38\88\tk3_38\0\tk4_38\0\tk5_38\0\tk6_38\0\kk0_38\0\kk1_38\0\kk2_38\0\kk3_38\0\kk4_38\0\kk5_38\0\kk6_38\0\dk0_38\0\dk1_38\0\dk2_38\0\dk3_38\0\dk4_38\0\dk5_38\0\dk6_38\0\tw0_38\0\tw1_38\0\tw2_38\0\tw3_38\0\tw4_38\0\tw5_38\0\tw6_38\0\tw7_38\0\tw8_38\88\te0_38\0\te1_38\0\te3_38\0\te2_38\0\te4_38\0\te5_38\0\te6_38\0\te7_38\0\te8_38\0\kw0_38\0\kw1_38\0\kw2_38\0\kw3_38\0\kw4_38\0\kw5_38\0\kw6_38\0\kw7_38\0\kw8_38\0\ke0_38\0\ke1_38\0\ke3_38\0\ke2_38\0\ke4_38\0\ke5_38\0\bw0_38\0\bw1_38\0\bw2_38\0\bw3_38\0\bw4_38\0\bw5_38\0\bw6_38\0\bw7_38\0\bw8_38\0\be0_38\0\be1_38\0\be3_38\0\be2_38\0\be4_38\0\be5_38\0\be8_38\0\be9_38\0\de6_38\0\de7_38\0\de8_38\0\sw0_38\0\sw1_38\0\sw2_38\0\sw3_38\0\sw4_38\0\sw5_38\0\sw6_38\0\sw7_38\0\sw8_38\0\se0_38\0\se1_38\0\se2_38\0\se3_38\0\se4_38\0\se5_38\0\hw0_38\0\hw1_38\0\hw2_38\0\hw3_38\0\hw4_38\0\hw5_38\0\hw6_38\0\hw7_38\0\hw8_38\0\he0_38\0\he1_38\0\he2_38\0\he3_38\0\he4_38\0\he5_38\0\pID_39\28999929\name_39\I. Ackworth\t_39\2\a_39\0\ctime_39\88\c_39\1\ip_39\127.0.0.1\ai_39\1\rs_39\0\cs_39\0\ss_39\0\ts_39\0\kills_39\0\deaths_39\1\cpc_39\0\cpa_39\0\cpd_39\0\ka_39\0\he_39\0\rev_39\0\rsp_39\0\rep_39\0\tre_39\0\drs_39\0\tmkl_39\0\tmdg_39\0\tmvd_39\0\su_39\0\ks_39\0\ds_39\1\rank_39\0\ban_39\0\kck_39\0\tco_39\0\tsl_39\88\tsm_39\0\tlw_39\0\ta0_39\88\ta1_39\0\ta2_39\0\ta3_39\0\ta4_39\0\ta5_39\0\ta6_39\0\ta7_39\0\ta8_39\0\ta9_39\0\ta10_39\0\ta11_39\0\ta12_39\0\ta13_39\0\tv0_39\0\tv1_39\0\tv2_39\0\tv3_39\0\tv4_39\0\tv5_39\0\tv6_39\0\tvp_39\0\kv0_39\0\kv1_39\0\kv2_39\0\kv3_39\0\kv4_39\0\kv5_39\0\kv6_39\0\bv0_39\0\bv1_39\0\bv2_39\0\bv3_39\0\bv4_39\0\bv5_39\0\bv6_39\0\kvr0_39\0\kvr1_39\0\kvr2_39\0\kvr3_39\0\kvr4_39\0\kvr5_39\0\kvr6_39\0\tk0_39\48\tk1_39\0\tk2_39\29\tk3_39\0\tk4_39\0\tk5_39\0\tk6_39\0\kk0_39\0\kk1_39\0\kk2_39\0\kk3_39\0\kk4_39\0\kk5_39\0\kk6_39\0\dk0_39\1\dk1_39\0\dk2_39\0\dk3_39\0\dk4_39\0\dk5_39\0\dk6_39\0\tw0_39\0\tw1_39\0\tw2_39\0\tw3_39\0\tw4_39\0\tw5_39\0\tw6_39\10\tw7_39\37\tw8_39\29\te0_39\0\te1_39\0\te3_39\0\te2_39\0\te4_39\0\te5_39\0\te6_39\0\te7_39\0\te8_39\0\kw0_39\0\kw1_39\0\kw2_39\0\kw3_39\0\kw4_39\0\kw5_39\0\kw6_39\0\kw7_39\0\kw8_39\0\ke0_39\0\ke1_39\0\ke3_39\0\ke2_39\0\ke4_39\0\ke5_39\0\bw0_39\0\bw1_39\0\bw2_39\0\bw3_39\0\bw4_39\0\bw5_39\0\bw6_39\1\bw7_39\0\bw8_39\0\be0_39\0\be1_39\0\be3_39\0\be2_39\0\be4_39\0\be5_39\0\be8_39\0\be9_39\0\de6_39\0\de7_39\0\de8_39\0\sw0_39\0\sw1_39\0\sw2_39\0\sw3_39\0\sw4_39\0\sw5_39\0\sw6_39\1\sw7_39\0\sw8_39\0\se0_39\0\se1_39\0\se2_39\0\se3_39\0\se4_39\0\se5_39\0\hw0_39\0\hw1_39\0\hw2_39\0\hw3_39\0\hw4_39\0\hw5_39\0\hw6_39\1\hw7_39\0\hw8_39\0\he0_39\0\he1_39\0\he2_39\0\he3_39\0\he4_39\0\he5_39\0\pID_40\28999944\name_40\O. Carlen\t_40\2\a_40\0\ctime_40\88\c_40\1\ip_40\127.0.0.1\ai_40\1\rs_40\0\cs_40\0\ss_40\0\ts_40\0\kills_40\0\deaths_40\0\cpc_40\0\cpa_40\0\cpd_40\0\ka_40\0\he_40\0\rev_40\0\rsp_40\0\rep_40\0\tre_40\0\drs_40\0\tmkl_40\0\tmdg_40\0\tmvd_40\0\su_40\0\ks_40\0\ds_40\0\rank_40\0\ban_40\0\kck_40\0\tco_40\0\tsl_40\0\tsm_40\88\tlw_40\0\ta0_40\88\ta1_40\0\ta2_40\0\ta3_40\0\ta4_40\0\ta5_40\0\ta6_40\0\ta7_40\0\ta8_40\0\ta9_40\0\ta10_40\0\ta11_40\0\ta12_40\0\ta13_40\0\tv0_40\0\tv1_40\0\tv2_40\0\tv3_40\0\tv4_40\0\tv5_40\0\tv6_40\0\tvp_40\0\kv0_40\0\kv1_40\0\kv2_40\0\kv3_40\0\kv4_40\0\kv5_40\0\kv6_40\0\bv0_40\0\bv1_40\0\bv2_40\0\bv3_40\0\bv4_40\0\bv5_40\0\bv6_40\0\kvr0_40\0\kvr1_40\0\kvr2_40\0\kvr3_40\0\kvr4_40\0\kvr5_40\0\kvr6_40\0\tk0_40\0\tk1_40\0\tk2_40\0\tk3_40\0\tk4_40\88\tk5_40\0\tk6_40\0\kk0_40\0\kk1_40\0\kk2_40\0\kk3_40\0\kk4_40\0\kk5_40\0\kk6_40\0\dk0_40\0\dk1_40\0\dk2_40\0\dk3_40\0\dk4_40\0\dk5_40\0\dk6_40\0\tw0_40\0\tw1_40\0\tw2_40\82\tw3_40\0\tw4_40\0\tw5_40\0\tw6_40\0\tw7_40\0\tw8_40\0\te0_40\0\te1_40\2\te3_40\3\te2_40\0\te4_40\0\te5_40\0\te6_40\0\te7_40\0\te8_40\0\kw0_40\0\kw1_40\0\kw2_40\0\kw3_40\0\kw4_40\0\kw5_40\0\kw6_40\0\kw7_40\0\kw8_40\0\ke0_40\0\ke1_40\0\ke3_40\0\ke2_40\0\ke4_40\0\ke5_40\0\bw0_40\0\bw1_40\0\bw2_40\0\bw3_40\0\bw4_40\0\bw5_40\0\bw6_40\0\bw7_40\0\bw8_40\0\be0_40\0\be1_40\0\be3_40\0\be2_40\0\be4_40\0\be5_40\0\be8_40\0\be9_40\0\de6_40\0\de7_40\0\de8_40\0\sw0_40\0\sw1_40\0\sw2_40\25\sw3_40\0\sw4_40\0\sw5_40\0\sw6_40\0\sw7_40\0\sw8_40\0\se0_40\0\se1_40\1\se2_40\0\se3_40\0\se4_40\0\se5_40\0\hw0_40\0\hw1_40\0\hw2_40\1\hw3_40\0\hw4_40\0\hw5_40\0\hw6_40\0\hw7_40\0\hw8_40\0\he0_40\0\he1_40\0\he2_40\0\he3_40\0\he4_40\0\he5_40\0\pID_41\28999960\name_41\M. Brassard\t_41\2\a_41\0\ctime_41\14\c_41\1\ip_41\127.0.0.1\ai_41\1\rs_41\2\cs_41\0\ss_41\0\ts_41\2\kills_41\0\deaths_41\0\cpc_41\0\cpa_41\0\cpd_41\0\ka_41\0\he_41\0\rev_41\1\rsp_41\0\rep_41\0\tre_41\0\drs_41\0\tmkl_41\0\tmdg_41\0\tmvd_41\0\su_41\0\ks_41\0\ds_41\0\rank_41\0\ban_41\0\kck_41\0\tco_41\0\tsl_41\0\tsm_41\14\tlw_41\0\ta0_41\14\ta1_41\0\ta2_41\0\ta3_41\0\ta4_41\0\ta5_41\0\ta6_41\0\ta7_41\0\ta8_41\0\ta9_41\0\ta10_41\0\ta11_41\0\ta12_41\0\ta13_41\0\tv0_41\0\tv1_41\0\tv2_41\0\tv3_41\0\tv4_41\0\tv5_41\0\tv6_41\0\tvp_41\0\kv0_41\0\kv1_41\0\kv2_41\0\kv3_41\0\kv4_41\0\kv5_41\0\kv6_41\0\bv0_41\0\bv1_41\0\bv2_41\0\bv3_41\0\bv4_41\0\bv5_41\0\bv6_41\0\kvr0_41\0\kvr1_41\0\kvr2_41\0\kvr3_41\0\kvr4_41\0\kvr5_41\0\kvr6_41\0\tk0_41\0\tk1_41\0\tk2_41\0\tk3_41\73\tk4_41\0\tk5_41\0\tk6_41\0\kk0_41\0\kk1_41\0\kk2_41\0\kk3_41\0\kk4_41\0\kk5_41\0\kk6_41\0\dk0_41\0\dk1_41\0\dk2_41\0\dk3_41\0\dk4_41\0\dk5_41\0\dk6_41\0\tw0_41\49\tw1_41\0\tw2_41\0\tw3_41\0\tw4_41\0\tw5_41\0\tw6_41\0\tw7_41\0\tw8_41\0\te0_41\0\te1_41\0\te3_41\19\te2_41\0\te4_41\4\te5_41\0\te6_41\0\te7_41\0\te8_41\0\kw0_41\0\kw1_41\0\kw2_41\0\kw3_41\0\kw4_41\0\kw5_41\0\kw6_41\0\kw7_41\0\kw8_41\0\ke0_41\0\ke1_41\0\ke3_41\0\ke2_41\0\ke4_41\0\ke5_41\0\bw0_41\0\bw1_41\0\bw2_41\0\bw3_41\0\bw4_41\0\bw5_41\0\bw6_41\0\bw7_41\0\bw8_41\0\be0_41\0\be1_41\0\be3_41\0\be2_41\0\be4_41\0\be5_41\0\be8_41\0\be9_41\0\de6_41\0\de7_41\0\de8_41\0\sw0_41\0\sw1_41\0\sw2_41\0\sw3_41\0\sw4_41\0\sw5_41\0\sw6_41\0\sw7_41\0\sw8_41\0\se0_41\0\se1_41\0\se2_41\0\se3_41\1\se4_41\1\se5_41\0\hw0_41\0\hw1_41\0\hw2_41\0\hw3_41\0\hw4_41\0\hw5_41\0\hw6_41\0\hw7_41\0\hw8_41\0\he0_41\0\he1_41\0\he2_41\0\he3_41\1\he4_41\1\he5_41\0\pID_42\28999902\name_42\S. Abdey\t_42\2\a_42\0\ctime_42\88\c_42\1\ip_42\127.0.0.1\ai_42\1\rs_42\1\cs_42\0\ss_42\0\ts_42\1\kills_42\0\deaths_42\0\cpc_42\0\cpa_42\0\cpd_42\0\ka_42\1\he_42\0\rev_42\0\rsp_42\0\rep_42\0\tre_42\0\drs_42\0\tmkl_42\0\tmdg_42\0\tmvd_42\0\su_42\0\ks_42\0\ds_42\0\rank_42\0\ban_42\0\kck_42\0\tco_42\0\tsl_42\0\tsm_42\88\tlw_42\0\ta0_42\88\ta1_42\0\ta2_42\0\ta3_42\0\ta4_42\0\ta5_42\0\ta6_42\0\ta7_42\0\ta8_42\0\ta9_42\0\ta10_42\0\ta11_42\0\ta12_42\0\ta13_42\0\tv0_42\0\tv1_42\0\tv2_42\0\tv3_42\0\tv4_42\0\tv5_42\0\tv6_42\0\tvp_42\0\kv0_42\0\kv1_42\0\kv2_42\0\kv3_42\0\kv4_42\0\kv5_42\0\kv6_42\0\bv0_42\0\bv1_42\0\bv2_42\0\bv3_42\0\bv4_42\0\bv5_42\0\bv6_42\0\kvr0_42\0\kvr1_42\0\kvr2_42\0\kvr3_42\0\kvr4_42\0\kvr5_42\0\kvr6_42\0\tk0_42\0\tk1_42\0\tk2_42\87\tk3_42\0\tk4_42\0\tk5_42\0\tk6_42\0\kk0_42\0\kk1_42\0\kk2_42\0\kk3_42\0\kk4_42\0\kk5_42\0\kk6_42\0\dk0_42\0\dk1_42\0\dk2_42\0\dk3_42\0\dk4_42\0\dk5_42\0\dk6_42\0\tw0_42\0\tw1_42\0\tw2_42\0\tw3_42\0\tw4_42\0\tw5_42\0\tw6_42\0\tw7_42\0\tw8_42\60\te0_42\0\te1_42\0\te3_42\26\te2_42\0\te4_42\0\te5_42\0\te6_42\0\te7_42\0\te8_42\0\kw0_42\0\kw1_42\0\kw2_42\0\kw3_42\0\kw4_42\0\kw5_42\0\kw6_42\0\kw7_42\0\kw8_42\0\ke0_42\0\ke1_42\0\ke3_42\0\ke2_42\0\ke4_42\0\ke5_42\0\bw0_42\0\bw1_42\0\bw2_42\0\bw3_42\0\bw4_42\0\bw5_42\0\bw6_42\0\bw7_42\0\bw8_42\0\be0_42\0\be1_42\0\be3_42\0\be2_42\0\be4_42\0\be5_42\0\be8_42\0\be9_42\0\de6_42\0\de7_42\0\de8_42\0\sw0_42\0\sw1_42\0\sw2_42\0\sw3_42\0\sw4_42\0\sw5_42\0\sw6_42\0\sw7_42\0\sw8_42\4\se0_42\0\se1_42\0\se2_42\0\se3_42\4\se4_42\0\se5_42\0\hw0_42\0\hw1_42\0\hw2_42\0\hw3_42\0\hw4_42\0\hw5_42\0\hw6_42\0\hw7_42\0\hw8_42\0\he0_42\0\he1_42\0\he2_42\0\he3_42\3\he4_42\0\he5_42\0\pID_43\28999999\name_43\S. Lindgren\t_43\2\a_43\0\ctime_43\88\c_43\1\ip_43\127.0.0.1\ai_43\1\rs_43\0\cs_43\0\ss_43\0\ts_43\0\kills_43\0\deaths_43\1\cpc_43\0\cpa_43\0\cpd_43\0\ka_43\0\he_43\0\rev_43\0\rsp_43\0\rep_43\0\tre_43\0\drs_43\0\tmkl_43\0\tmdg_43\0\tmvd_43\0\su_43\0\ks_43\0\ds_43\1\rank_43\0\ban_43\0\kck_43\0\tco_43\0\tsl_43\0\tsm_43\88\tlw_43\0\ta0_43\88\ta1_43\0\ta2_43\0\ta3_43\0\ta4_43\0\ta5_43\0\ta6_43\0\ta7_43\0\ta8_43\0\ta9_43\0\ta10_43\0\ta11_43\0\ta12_43\0\ta13_43\0\tv0_43\0\tv1_43\0\tv2_43\0\tv3_43\0\tv4_43\0\tv5_43\0\tv6_43\0\tvp_43\0\kv0_43\0\kv1_43\0\kv2_43\0\kv3_43\0\kv4_43\0\kv5_43\0\kv6_43\0\bv0_43\0\bv1_43\0\bv2_43\0\bv3_43\0\bv4_43\0\bv5_43\0\bv6_43\0\kvr0_43\0\kvr1_43\0\kvr2_43\0\kvr3_43\0\kvr4_43\0\kvr5_43\0\kvr6_43\0\tk0_43\0\tk1_43\0\tk2_43\0\tk3_43\0\tk4_43\24\tk5_43\52\tk6_43\0\kk0_43\0\kk1_43\0\kk2_43\0\kk3_43\0\kk4_43\0\kk5_43\0\kk6_43\0\dk0_43\0\dk1_43\0\dk2_43\0\dk3_43\0\dk4_43\0\dk5_43\1\dk6_43\0\tw0_43\0\tw1_43\0\tw2_43\24\tw3_43\41\tw4_43\0\tw5_43\0\tw6_43\0\tw7_43\0\tw8_43\0\te0_43\0\te1_43\0\te3_43\11\te2_43\0\te4_43\0\te5_43\0\te6_43\0\te7_43\0\te8_43\0\kw0_43\0\kw1_43\0\kw2_43\0\kw3_43\0\kw4_43\0\kw5_43\0\kw6_43\0\kw7_43\0\kw8_43\0\ke0_43\0\ke1_43\0\ke3_43\0\ke2_43\0\ke4_43\0\ke5_43\0\bw0_43\0\bw1_43\0\bw2_43\0\bw3_43\0\bw4_43\0\bw5_43\0\bw6_43\0\bw7_43\0\bw8_43\0\be0_43\0\be1_43\0\be3_43\1\be2_43\0\be4_43\0\be5_43\0\be8_43\0\be9_43\0\de6_43\0\de7_43\0\de8_43\0\sw0_43\0\sw1_43\0\sw2_43\0\sw3_43\0\sw4_43\0\sw5_43\0\sw6_43\0\sw7_43\0\sw8_43\0\se0_43\0\se1_43\0\se2_43\0\se3_43\0\se4_43\0\se5_43\0\hw0_43\0\hw1_43\0\hw2_43\0\hw3_43\0\hw4_43\0\hw5_43\0\hw6_43\0\hw7_43\0\hw8_43\0\he0_43\0\he1_43\0\he2_43\0\he3_43\0\he4_43\0\he5_43\0\pID_44\28999945\name_44\J. Jonsson\t_44\2\a_44\0\ctime_44\88\c_44\1\ip_44\127.0.0.1\ai_44\1\rs_44\2\cs_44\0\ss_44\0\ts_44\2\kills_44\0\deaths_44\0\cpc_44\0\cpa_44\1\cpd_44\0\ka_44\1\he_44\0\rev_44\0\rsp_44\0\rep_44\0\tre_44\0\drs_44\0\tmkl_44\0\tmdg_44\0\tmvd_44\0\su_44\0\ks_44\0\ds_44\0\rank_44\0\ban_44\0\kck_44\0\tco_44\0\tsl_44\88\tsm_44\0\tlw_44\0\ta0_44\88\ta1_44\0\ta2_44\0\ta3_44\0\ta4_44\0\ta5_44\0\ta6_44\0\ta7_44\0\ta8_44\0\ta9_44\0\ta10_44\0\ta11_44\0\ta12_44\0\ta13_44\0\tv0_44\0\tv1_44\0\tv2_44\0\tv3_44\0\tv4_44\6\tv5_44\0\tv6_44\0\tvp_44\0\kv0_44\0\kv1_44\0\kv2_44\0\kv3_44\0\kv4_44\0\kv5_44\0\kv6_44\0\bv0_44\0\bv1_44\0\bv2_44\0\bv3_44\0\bv4_44\0\bv5_44\0\bv6_44\0\kvr0_44\0\kvr1_44\0\kvr2_44\0\kvr3_44\0\kvr4_44\0\kvr5_44\0\kvr6_44\0\tk0_44\0\tk1_44\0\tk2_44\88\tk3_44\0\tk4_44\0\tk5_44\0\tk6_44\0\kk0_44\0\kk1_44\0\kk2_44\0\kk3_44\0\kk4_44\0\kk5_44\0\kk6_44\0\dk0_44\0\dk1_44\0\dk2_44\0\dk3_44\0\dk4_44\0\dk5_44\0\dk6_44\0\tw0_44\0\tw1_44\0\tw2_44\0\tw3_44\0\tw4_44\0\tw5_44\4\tw6_44\0\tw7_44\0\tw8_44\76\te0_44\0\te1_44\0\te3_44\1\te2_44\0\te4_44\0\te5_44\0\te6_44\0\te7_44\0\te8_44\0\kw0_44\0\kw1_44\0\kw2_44\0\kw3_44\0\kw4_44\0\kw5_44\0\kw6_44\0\kw7_44\0\kw8_44\0\ke0_44\0\ke1_44\0\ke3_44\0\ke2_44\0\ke4_44\0\ke5_44\0\bw0_44\0\bw1_44\0\bw2_44\0\bw3_44\0\bw4_44\0\bw5_44\0\bw6_44\0\bw7_44\0\bw8_44\0\be0_44\0\be1_44\0\be3_44\0\be2_44\0\be4_44\0\be5_44\0\be8_44\0\be9_44\0\de6_44\0\de7_44\0\de8_44\0\sw0_44\0\sw1_44\0\sw2_44\0\sw3_44\0\sw4_44\0\sw5_44\15\sw6_44\0\sw7_44\0\sw8_44\7\se0_44\0\se1_44\0\se2_44\0\se3_44\0\se4_44\0\se5_44\0\hw0_44\0\hw1_44\0\hw2_44\0\hw3_44\0\hw4_44\0\hw5_44\1\hw6_44\0\hw7_44\0\hw8_44\0\he0_44\0\he1_44\0\he2_44\0\he3_44\0\he4_44\0\he5_44\0\pID_45\28999881\name_45\R. Smedberg\t_45\2\a_45\0\ctime_45\88\c_45\1\ip_45\127.0.0.1\ai_45\1\rs_45\0\cs_45\0\ss_45\0\ts_45\0\kills_45\0\deaths_45\1\cpc_45\0\cpa_45\0\cpd_45\0\ka_45\0\he_45\0\rev_45\0\rsp_45\0\rep_45\0\tre_45\0\drs_45\0\tmkl_45\0\tmdg_45\0\tmvd_45\0\su_45\0\ks_45\0\ds_45\1\rank_45\0\ban_45\0\kck_45\0\tco_45\0\tsl_45\0\tsm_45\88\tlw_45\0\ta0_45\88\ta1_45\0\ta2_45\0\ta3_45\0\ta4_45\0\ta5_45\0\ta6_45\0\ta7_45\0\ta8_45\0\ta9_45\0\ta10_45\0\ta11_45\0\ta12_45\0\ta13_45\0\tv0_45\0\tv1_45\0\tv2_45\0\tv3_45\0\tv4_45\0\tv5_45\0\tv6_45\0\tvp_45\0\kv0_45\0\kv1_45\0\kv2_45\0\kv3_45\0\kv4_45\0\kv5_45\0\kv6_45\0\bv0_45\0\bv1_45\0\bv2_45\0\bv3_45\0\bv4_45\0\bv5_45\0\bv6_45\0\kvr0_45\0\kvr1_45\0\kvr2_45\0\kvr3_45\0\kvr4_45\0\kvr5_45\0\kvr6_45\0\tk0_45\17\tk1_45\0\tk2_45\0\tk3_45\0\tk4_45\59\tk5_45\0\tk6_45\0\kk0_45\0\kk1_45\0\kk2_45\0\kk3_45\0\kk4_45\0\kk5_45\0\kk6_45\0\dk0_45\0\dk1_45\0\dk2_45\0\dk3_45\0\dk4_45\1\dk5_45\0\dk6_45\0\tw0_45\0\tw1_45\0\tw2_45\59\tw3_45\0\tw4_45\0\tw5_45\0\tw6_45\0\tw7_45\17\tw8_45\0\te0_45\0\te1_45\0\te3_45\0\te2_45\0\te4_45\0\te5_45\0\te6_45\0\te7_45\0\te8_45\0\kw0_45\0\kw1_45\0\kw2_45\0\kw3_45\0\kw4_45\0\kw5_45\0\kw6_45\0\kw7_45\0\kw8_45\0\ke0_45\0\ke1_45\0\ke3_45\0\ke2_45\0\ke4_45\0\ke5_45\0\bw0_45\0\bw1_45\0\bw2_45\1\bw3_45\0\bw4_45\0\bw5_45\0\bw6_45\0\bw7_45\0\bw8_45\0\be0_45\0\be1_45\0\be3_45\0\be2_45\0\be4_45\0\be5_45\0\be8_45\0\be9_45\0\de6_45\0\de7_45\0\de8_45\0\sw0_45\0\sw1_45\0\sw2_45\11\sw3_45\0\sw4_45\0\sw5_45\0\sw6_45\0\sw7_45\0\sw8_45\0\se0_45\0\se1_45\0\se2_45\0\se3_45\0\se4_45\0\se5_45\0\hw0_45\0\hw1_45\0\hw2_45\0\hw3_45\0\hw4_45\0\hw5_45\0\hw6_45\0\hw7_45\0\hw8_45\0\he0_45\0\he1_45\0\he2_45\0\he3_45\0\he4_45\0\he5_45\0\pID_46\28999897\name_46\C. Bergqvist\t_46\2\a_46\0\ctime_46\88\c_46\1\ip_46\127.0.0.1\ai_46\1\rs_46\4\cs_46\0\ss_46\4\ts_46\0\kills_46\2\deaths_46\0\cpc_46\0\cpa_46\0\cpd_46\0\ka_46\0\he_46\0\rev_46\0\rsp_46\0\rep_46\0\tre_46\0\drs_46\0\tmkl_46\0\tmdg_46\0\tmvd_46\0\su_46\0\ks_46\2\ds_46\0\rank_46\0\ban_46\0\kck_46\0\tco_46\0\tsl_46\0\tsm_46\88\tlw_46\0\ta0_46\88\ta1_46\0\ta2_46\0\ta3_46\0\ta4_46\0\ta5_46\0\ta6_46\0\ta7_46\0\ta8_46\0\ta9_46\0\ta10_46\0\ta11_46\0\ta12_46\0\ta13_46\0\mvns_46\28999928\mvks_46\1\mvns_46\28999885\mvks_46\1\ers_46\1\tv0_46\43\tv1_46\0\tv2_46\0\tv3_46\0\tv4_46\0\tv5_46\0\tv6_46\0\tvp_46\0\kv0_46\1\kv1_46\0\kv2_46\0\kv3_46\0\kv4_46\0\kv5_46\0\kv6_46\0\bv0_46\0\bv1_46\0\bv2_46\0\bv3_46\0\bv4_46\0\bv5_46\0\bv6_46\0\kvr0_46\0\kvr1_46\0\kvr2_46\0\kvr3_46\0\kvr4_46\0\kvr5_46\0\kvr6_46\0\tk0_46\0\tk1_46\0\tk2_46\0\tk3_46\81\tk4_46\0\tk5_46\0\tk6_46\0\kk0_46\0\kk1_46\0\kk2_46\0\kk3_46\2\kk4_46\0\kk5_46\0\kk6_46\0\dk0_46\0\dk1_46\0\dk2_46\0\dk3_46\0\dk4_46\0\dk5_46\0\dk6_46\0\tw0_46\20\tw1_46\0\tw2_46\0\tw3_46\0\tw4_46\0\tw5_46\0\tw6_46\0\tw7_46\0\tw8_46\0\te0_46\0\te1_46\0\te3_46\17\te2_46\0\te4_46\0\te5_46\0\te6_46\0\te7_46\0\te8_46\0\kw0_46\0\kw1_46\0\kw2_46\0\kw3_46\0\kw4_46\0\kw5_46\0\kw6_46\0\kw7_46\0\kw8_46\0\ke0_46\0\ke1_46\0\ke3_46\1\ke2_46\0\ke4_46\0\ke5_46\0\bw0_46\0\bw1_46\0\bw2_46\0\bw3_46\0\bw4_46\0\bw5_46\0\bw6_46\0\bw7_46\0\bw8_46\0\be0_46\0\be1_46\0\be3_46\0\be2_46\0\be4_46\0\be5_46\0\be8_46\0\be9_46\0\de6_46\0\de7_46\0\de8_46\0\sw0_46\0\sw1_46\0\sw2_46\0\sw3_46\0\sw4_46\0\sw5_46\0\sw6_46\0\sw7_46\0\sw8_46\0\se0_46\0\se1_46\0\se2_46\0\se3_46\3\se4_46\0\se5_46\0\hw0_46\0\hw1_46\0\hw2_46\0\hw3_46\0\hw4_46\0\hw5_46\0\hw6_46\0\hw7_46\0\hw8_46\0\he0_46\0\he1_46\0\he2_46\0\he3_46\3\he4_46\0\he5_46\0\pID_47\28999941\name_47\J. Price\t_47\2\a_47\0\ctime_47\88\c_47\1\ip_47\127.0.0.1\ai_47\1\rs_47\0\cs_47\0\ss_47\0\ts_47\0\kills_47\0\deaths_47\0\cpc_47\0\cpa_47\0\cpd_47\0\ka_47\0\he_47\0\rev_47\0\rsp_47\0\rep_47\0\tre_47\0\drs_47\0\tmkl_47\0\tmdg_47\0\tmvd_47\0\su_47\0\ks_47\0\ds_47\0\rank_47\0\ban_47\0\kck_47\0\tco_47\0\tsl_47\0\tsm_47\88\tlw_47\0\ta0_47\88\ta1_47\0\ta2_47\0\ta3_47\0\ta4_47\0\ta5_47\0\ta6_47\0\ta7_47\0\ta8_47\0\ta9_47\0\ta10_47\0\ta11_47\0\ta12_47\0\ta13_47\0\tv0_47\0\tv1_47\0\tv2_47\0\tv3_47\0\tv4_47\0\tv5_47\0\tv6_47\0\tvp_47\0\kv0_47\0\kv1_47\0\kv2_47\0\kv3_47\0\kv4_47\0\kv5_47\0\kv6_47\0\bv0_47\0\bv1_47\0\bv2_47\0\bv3_47\0\bv4_47\0\bv5_47\0\bv6_47\0\kvr0_47\0\kvr1_47\0\kvr2_47\0\kvr3_47\0\kvr4_47\0\kvr5_47\0\kvr6_47\0\tk0_47\0\tk1_47\0\tk2_47\0\tk3_47\0\tk4_47\0\tk5_47\88\tk6_47\0\kk0_47\0\kk1_47\0\kk2_47\0\kk3_47\0\kk4_47\0\kk5_47\0\kk6_47\0\dk0_47\0\dk1_47\0\dk2_47\0\dk3_47\0\dk4_47\0\dk5_47\0\dk6_47\0\tw0_47\0\tw1_47\0\tw2_47\0\tw3_47\80\tw4_47\0\tw5_47\0\tw6_47\0\tw7_47\0\tw8_47\0\te0_47\0\te1_47\0\te3_47\8\te2_47\0\te4_47\0\te5_47\0\te6_47\0\te7_47\0\te8_47\0\kw0_47\0\kw1_47\0\kw2_47\0\kw3_47\0\kw4_47\0\kw5_47\0\kw6_47\0\kw7_47\0\kw8_47\0\ke0_47\0\ke1_47\0\ke3_47\0\ke2_47\0\ke4_47\0\ke5_47\0\bw0_47\0\bw1_47\0\bw2_47\0\bw3_47\0\bw4_47\0\bw5_47\0\bw6_47\0\bw7_47\0\bw8_47\0\be0_47\0\be1_47\0\be3_47\0\be2_47\0\be4_47\0\be5_47\0\be8_47\0\be9_47\0\de6_47\0\de7_47\0\de8_47\0\sw0_47\0\sw1_47\0\sw2_47\0\sw3_47\9\sw4_47\0\sw5_47\0\sw6_47\0\sw7_47\0\sw8_47\0\se0_47\0\se1_47\0\se2_47\0\se3_47\3\se4_47\0\se5_47\0\hw0_47\0\hw1_47\0\hw2_47\0\hw3_47\0\hw4_47\0\hw5_47\0\hw6_47\0\hw7_47\0\hw8_47\0\he0_47\0\he1_47\0\he2_47\0\he3_47\2\he4_47\0\he5_47\0\pID_48\28999994\name_48\L. Gustavsson\t_48\2\a_48\0\ctime_48\88\c_48\1\ip_48\127.0.0.1\ai_48\1\rs_48\1\cs_48\0\ss_48\0\ts_48\1\kills_48\0\deaths_48\0\cpc_48\0\cpa_48\1\cpd_48\0\ka_48\0\he_48\0\rev_48\0\rsp_48\0\rep_48\0\tre_48\0\drs_48\0\tmkl_48\0\tmdg_48\0\tmvd_48\0\su_48\0\ks_48\0\ds_48\0\rank_48\0\ban_48\0\kck_48\0\tco_48\0\tsl_48\0\tsm_48\88\tlw_48\0\ta0_48\88\ta1_48\0\ta2_48\0\ta3_48\0\ta4_48\0\ta5_48\0\ta6_48\0\ta7_48\0\ta8_48\0\ta9_48\0\ta10_48\0\ta11_48\0\ta12_48\0\ta13_48\0\tv0_48\0\tv1_48\0\tv2_48\0\tv3_48\0\tv4_48\1\tv5_48\0\tv6_48\0\tvp_48\0\kv0_48\0\kv1_48\0\kv2_48\0\kv3_48\0\kv4_48\0\kv5_48\0\kv6_48\0\bv0_48\0\bv1_48\0\bv2_48\0\bv3_48\0\bv4_48\0\bv5_48\0\bv6_48\0\kvr0_48\0\kvr1_48\0\kvr2_48\0\kvr3_48\0\kvr4_48\0\kvr5_48\0\kvr6_48\0\tk0_48\88\tk1_48\0\tk2_48\0\tk3_48\0\tk4_48\0\tk5_48\0\tk6_48\0\kk0_48\0\kk1_48\0\kk2_48\0\kk3_48\0\kk4_48\0\kk5_48\0\kk6_48\0\dk0_48\0\dk1_48\0\dk2_48\0\dk3_48\0\dk4_48\0\dk5_48\0\dk6_48\0\tw0_48\0\tw1_48\0\tw2_48\0\tw3_48\0\tw4_48\0\tw5_48\4\tw6_48\3\tw7_48\79\tw8_48\0\te0_48\0\te1_48\0\te3_48\0\te2_48\0\te4_48\0\te5_48\0\te6_48\0\te7_48\0\te8_48\0\kw0_48\0\kw1_48\0\kw2_48\0\kw3_48\0\kw4_48\0\kw5_48\0\kw6_48\0\kw7_48\0\kw8_48\0\ke0_48\0\ke1_48\0\ke3_48\0\ke2_48\0\ke4_48\0\ke5_48\0\bw0_48\0\bw1_48\0\bw2_48\0\bw3_48\0\bw4_48\0\bw5_48\0\bw6_48\0\bw7_48\0\bw8_48\0\be0_48\0\be1_48\0\be3_48\0\be2_48\0\be4_48\0\be5_48\0\be8_48\0\be9_48\0\de6_48\0\de7_48\0\de8_48\0\sw0_48\0\sw1_48\0\sw2_48\0\sw3_48\0\sw4_48\0\sw5_48\15\sw6_48\0\sw7_48\30\sw8_48\0\se0_48\0\se1_48\0\se2_48\0\se3_48\0\se4_48\0\se5_48\0\hw0_48\0\hw1_48\0\hw2_48\0\hw3_48\0\hw4_48\0\hw5_48\0\hw6_48\0\hw7_48\1\hw8_48\0\he0_48\0\he1_48\0\he2_48\0\he3_48\0\he4_48\0\he5_48\0\pID_49\28999984\name_49\M. Fritze\t_49\2\a_49\0\ctime_49\88\c_49\1\ip_49\127.0.0.1\ai_49\1\rs_49\2\cs_49\0\ss_49\0\ts_49\2\kills_49\0\deaths_49\0\cpc_49\1\cpa_49\0\cpd_49\0\ka_49\0\he_49\0\rev_49\0\rsp_49\0\rep_49\0\tre_49\0\drs_49\0\tmkl_49\0\tmdg_49\0\tmvd_49\0\su_49\0\ks_49\0\ds_49\0\rank_49\0\ban_49\0\kck_49\0\tco_49\0\tsl_49\88\tsm_49\0\tlw_49\0\ta0_49\88\ta1_49\0\ta2_49\0\ta3_49\0\ta4_49\0\ta5_49\0\ta6_49\0\ta7_49\0\ta8_49\0\ta9_49\0\ta10_49\0\ta11_49\0\ta12_49\0\ta13_49\0\tv0_49\0\tv1_49\0\tv2_49\0\tv3_49\0\tv4_49\0\tv5_49\0\tv6_49\0\tvp_49\0\kv0_49\0\kv1_49\0\kv2_49\0\kv3_49\0\kv4_49\0\kv5_49\0\kv6_49\0\bv0_49\0\bv1_49\0\bv2_49\0\bv3_49\0\bv4_49\0\bv5_49\0\bv6_49\0\kvr0_49\0\kvr1_49\0\kvr2_49\0\kvr3_49\0\kvr4_49\0\kvr5_49\0\kvr6_49\0\tk0_49\88\tk1_49\0\tk2_49\0\tk3_49\0\tk4_49\0\tk5_49\0\tk6_49\0\kk0_49\0\kk1_49\0\kk2_49\0\kk3_49\0\kk4_49\0\kk5_49\0\kk6_49\0\dk0_49\0\dk1_49\0\dk2_49\0\dk3_49\0\dk4_49\0\dk5_49\0\dk6_49\0\tw0_49\0\tw1_49\0\tw2_49\0\tw3_49\0\tw4_49\0\tw5_49\3\tw6_49\5\tw7_49\79\tw8_49\0\te0_49\0\te1_49\0\te3_49\0\te2_49\0\te4_49\0\te5_49\0\te6_49\0\te7_49\0\te8_49\0\kw0_49\0\kw1_49\0\kw2_49\0\kw3_49\0\kw4_49\0\kw5_49\0\kw6_49\0\kw7_49\0\kw8_49\0\ke0_49\0\ke1_49\0\ke3_49\0\ke2_49\0\ke4_49\0\ke5_49\0\bw0_49\0\bw1_49\0\bw2_49\0\bw3_49\0\bw4_49\0\bw5_49\0\bw6_49\0\bw7_49\0\bw8_49\0\be0_49\0\be1_49\0\be3_49\0\be2_49\0\be4_49\0\be5_49\0\be8_49\0\be9_49\0\de6_49\0\de7_49\0\de8_49\0\sw0_49\0\sw1_49\0\sw2_49\0\sw3_49\0\sw4_49\0\sw5_49\15\sw6_49\1\sw7_49\60\sw8_49\0\se0_49\0\se1_49\0\se2_49\0\se3_49\0\se4_49\0\se5_49\0\hw0_49\0\hw1_49\0\hw2_49\0\hw3_49\0\hw4_49\0\hw5_49\1\hw6_49\1\hw7_49\0\hw8_49\0\he0_49\0\he1_49\0\he2_49\0\he3_49\0\he4_49\0\he5_49\0\pID_50\28999936\name_50\M. Eriksson\t_50\2\a_50\0\ctime_50\88\c_50\1\ip_50\127.0.0.1\ai_50\1\rs_50\0\cs_50\0\ss_50\0\ts_50\0\kills_50\0\deaths_50\1\cpc_50\0\cpa_50\0\cpd_50\0\ka_50\0\he_50\0\rev_50\0\rsp_50\0\rep_50\0\tre_50\0\drs_50\0\tmkl_50\0\tmdg_50\0\tmvd_50\0\su_50\0\ks_50\0\ds_50\1\rank_50\0\ban_50\0\kck_50\0\tco_50\0\tsl_50\0\tsm_50\88\tlw_50\0\ta0_50\88\ta1_50\0\ta2_50\0\ta3_50\0\ta4_50\0\ta5_50\0\ta6_50\0\ta7_50\0\ta8_50\0\ta9_50\0\ta10_50\0\ta11_50\0\ta12_50\0\ta13_50\0\tv0_50\0\tv1_50\0\tv2_50\0\tv3_50\0\tv4_50\0\tv5_50\0\tv6_50\0\tvp_50\0\kv0_50\0\kv1_50\0\kv2_50\0\kv3_50\0\kv4_50\0\kv5_50\0\kv6_50\0\bv0_50\0\bv1_50\0\bv2_50\0\bv3_50\0\bv4_50\0\bv5_50\0\bv6_50\0\kvr0_50\0\kvr1_50\0\kvr2_50\0\kvr3_50\0\kvr4_50\0\kvr5_50\0\kvr6_50\0\tk0_50\19\tk1_50\0\tk2_50\0\tk3_50\0\tk4_50\0\tk5_50\0\tk6_50\57\kk0_50\0\kk1_50\0\kk2_50\0\kk3_50\0\kk4_50\0\kk5_50\0\kk6_50\0\dk0_50\0\dk1_50\0\dk2_50\0\dk3_50\0\dk4_50\0\dk5_50\0\dk6_50\1\tw0_50\0\tw1_50\0\tw2_50\0\tw3_50\0\tw4_50\40\tw5_50\0\tw6_50\0\tw7_50\19\tw8_50\0\te0_50\0\te1_50\0\te3_50\17\te2_50\0\te4_50\0\te5_50\0\te6_50\0\te7_50\0\te8_50\0\kw0_50\0\kw1_50\0\kw2_50\0\kw3_50\0\kw4_50\0\kw5_50\0\kw6_50\0\kw7_50\0\kw8_50\0\ke0_50\0\ke1_50\0\ke3_50\0\ke2_50\0\ke4_50\0\ke5_50\0\bw0_50\0\bw1_50\0\bw2_50\0\bw3_50\0\bw4_50\0\bw5_50\0\bw6_50\0\bw7_50\0\bw8_50\0\be0_50\0\be1_50\0\be3_50\1\be2_50\0\be4_50\0\be5_50\0\be8_50\0\be9_50\0\de6_50\0\de7_50\0\de8_50\0\sw0_50\0\sw1_50\0\sw2_50\0\sw3_50\0\sw4_50\0\sw5_50\0\sw6_50\0\sw7_50\0\sw8_50\0\se0_50\0\se1_50\0\se2_50\0\se3_50\1\se4_50\0\se5_50\0\hw0_50\0\hw1_50\0\hw2_50\0\hw3_50\0\hw4_50\0\hw5_50\0\hw6_50\0\hw7_50\0\hw8_50\0\he0_50\0\he1_50\0\he2_50\0\he3_50\1\he4_50\0\he5_50\0\pID_51\28999956\name_51\D. Wiksten\t_51\2\a_51\0\ctime_51\88\c_51\1\ip_51\127.0.0.1\ai_51\1\rs_51\0\cs_51\0\ss_51\0\ts_51\0\kills_51\0\deaths_51\0\cpc_51\0\cpa_51\0\cpd_51\0\ka_51\0\he_51\0\rev_51\0\rsp_51\0\rep_51\0\tre_51\0\drs_51\0\tmkl_51\0\tmdg_51\0\tmvd_51\0\su_51\0\ks_51\0\ds_51\0\rank_51\0\ban_51\0\kck_51\0\tco_51\0\tsl_51\0\tsm_51\88\tlw_51\0\ta0_51\88\ta1_51\0\ta2_51\0\ta3_51\0\ta4_51\0\ta5_51\0\ta6_51\0\ta7_51\0\ta8_51\0\ta9_51\0\ta10_51\0\ta11_51\0\ta12_51\0\ta13_51\0\tv0_51\0\tv1_51\0\tv2_51\0\tv3_51\0\tv4_51\0\tv5_51\0\tv6_51\0\tvp_51\0\kv0_51\0\kv1_51\0\kv2_51\0\kv3_51\0\kv4_51\0\kv5_51\0\kv6_51\0\bv0_51\0\bv1_51\0\bv2_51\0\bv3_51\0\bv4_51\0\bv5_51\0\bv6_51\0\kvr0_51\0\kvr1_51\0\kvr2_51\0\kvr3_51\0\kvr4_51\0\kvr5_51\0\kvr6_51\0\tk0_51\0\tk1_51\0\tk2_51\0\tk3_51\88\tk4_51\0\tk5_51\0\tk6_51\0\kk0_51\0\kk1_51\0\kk2_51\0\kk3_51\0\kk4_51\0\kk5_51\0\kk6_51\0\dk0_51\0\dk1_51\0\dk2_51\0\dk3_51\0\dk4_51\0\dk5_51\0\dk6_51\0\tw0_51\82\tw1_51\0\tw2_51\0\tw3_51\0\tw4_51\0\tw5_51\0\tw6_51\0\tw7_51\0\tw8_51\0\te0_51\0\te1_51\0\te3_51\5\te2_51\0\te4_51\0\te5_51\0\te6_51\0\te7_51\0\te8_51\0\kw0_51\0\kw1_51\0\kw2_51\0\kw3_51\0\kw4_51\0\kw5_51\0\kw6_51\0\kw7_51\0\kw8_51\0\ke0_51\0\ke1_51\0\ke3_51\0\ke2_51\0\ke4_51\0\ke5_51\0\bw0_51\0\bw1_51\0\bw2_51\0\bw3_51\0\bw4_51\0\bw5_51\0\bw6_51\0\bw7_51\0\bw8_51\0\be0_51\0\be1_51\0\be3_51\0\be2_51\0\be4_51\0\be5_51\0\be8_51\0\be9_51\0\de6_51\0\de7_51\0\de8_51\0\sw0_51\0\sw1_51\0\sw2_51\0\sw3_51\0\sw4_51\0\sw5_51\0\sw6_51\0\sw7_51\0\sw8_51\0\se0_51\0\se1_51\0\se2_51\0\se3_51\1\se4_51\0\se5_51\0\hw0_51\0\hw1_51\0\hw2_51\0\hw3_51\0\hw4_51\0\hw5_51\0\hw6_51\0\hw7_51\0\hw8_51\0\he0_51\0\he1_51\0\he2_51\0\he3_51\0\he4_51\0\he5_51\0\pID_52\28999908\name_52\J. Hartling\t_52\2\a_52\0\ctime_52\88\c_52\1\ip_52\127.0.0.1\ai_52\1\rs_52\0\cs_52\0\ss_52\0\ts_52\0\kills_52\0\deaths_52\0\cpc_52\0\cpa_52\0\cpd_52\0\ka_52\0\he_52\0\rev_52\0\rsp_52\0\rep_52\0\tre_52\0\drs_52\0\tmkl_52\0\tmdg_52\0\tmvd_52\0\su_52\0\ks_52\0\ds_52\0\rank_52\0\ban_52\0\kck_52\0\tco_52\0\tsl_52\0\tsm_52\88\tlw_52\0\ta0_52\88\ta1_52\0\ta2_52\0\ta3_52\0\ta4_52\0\ta5_52\0\ta6_52\0\ta7_52\0\ta8_52\0\ta9_52\0\ta10_52\0\ta11_52\0\ta12_52\0\ta13_52\0\tv0_52\0\tv1_52\0\tv2_52\0\tv3_52\0\tv4_52\0\tv5_52\0\tv6_52\0\tvp_52\0\kv0_52\0\kv1_52\0\kv2_52\0\kv3_52\0\kv4_52\0\kv5_52\0\kv6_52\0\bv0_52\0\bv1_52\0\bv2_52\0\bv3_52\0\bv4_52\0\bv5_52\0\bv6_52\0\kvr0_52\0\kvr1_52\0\kvr2_52\0\kvr3_52\0\kvr4_52\0\kvr5_52\0\kvr6_52\0\tk0_52\0\tk1_52\0\tk2_52\0\tk3_52\0\tk4_52\0\tk5_52\88\tk6_52\0\kk0_52\0\kk1_52\0\kk2_52\0\kk3_52\0\kk4_52\0\kk5_52\0\kk6_52\0\dk0_52\0\dk1_52\0\dk2_52\0\dk3_52\0\dk4_52\0\dk5_52\0\dk6_52\0\tw0_52\0\tw1_52\0\tw2_52\0\tw3_52\81\tw4_52\0\tw5_52\0\tw6_52\0\tw7_52\0\tw8_52\0\te0_52\0\te1_52\0\te3_52\7\te2_52\0\te4_52\0\te5_52\0\te6_52\0\te7_52\0\te8_52\0\kw0_52\0\kw1_52\0\kw2_52\0\kw3_52\0\kw4_52\0\kw5_52\0\kw6_52\0\kw7_52\0\kw8_52\0\ke0_52\0\ke1_52\0\ke3_52\0\ke2_52\0\ke4_52\0\ke5_52\0\bw0_52\0\bw1_52\0\bw2_52\0\bw3_52\0\bw4_52\0\bw5_52\0\bw6_52\0\bw7_52\0\bw8_52\0\be0_52\0\be1_52\0\be3_52\0\be2_52\0\be4_52\0\be5_52\0\be8_52\0\be9_52\0\de6_52\0\de7_52\0\de8_52\0\sw0_52\0\sw1_52\0\sw2_52\0\sw3_52\38\sw4_52\0\sw5_52\0\sw6_52\0\sw7_52\0\sw8_52\0\se0_52\0\se1_52\0\se2_52\0\se3_52\0\se4_52\0\se5_52\0\hw0_52\0\hw1_52\0\hw2_52\0\hw3_52\1\hw4_52\0\hw5_52\0\hw6_52\0\hw7_52\0\hw8_52\0\he0_52\0\he1_52\0\he2_52\0\he3_52\0\he4_52\0\he5_52\0\pID_53\28999923\name_53\E. Smith\t_53\2\a_53\0\ctime_53\88\c_53\1\ip_53\127.0.0.1\ai_53\1\rs_53\3\cs_53\0\ss_53\2\ts_53\1\kills_53\1\deaths_53\0\cpc_53\0\cpa_53\0\cpd_53\1\ka_53\0\he_53\0\rev_53\0\rsp_53\0\rep_53\0\tre_53\0\drs_53\0\tmkl_53\0\tmdg_53\0\tmvd_53\0\su_53\0\ks_53\1\ds_53\0\rank_53\0\ban_53\0\kck_53\0\tco_53\0\tsl_53\0\tsm_53\88\tlw_53\0\ta0_53\88\ta1_53\0\ta2_53\0\ta3_53\0\ta4_53\0\ta5_53\0\ta6_53\0\ta7_53\0\ta8_53\0\ta9_53\0\ta10_53\0\ta11_53\0\ta12_53\0\ta13_53\0\mvns_53\28999904\mvks_53\1\tv0_53\0\tv1_53\0\tv2_53\0\tv3_53\0\tv4_53\0\tv5_53\0\tv6_53\0\tvp_53\0\kv0_53\0\kv1_53\0\kv2_53\0\kv3_53\0\kv4_53\0\kv5_53\0\kv6_53\0\bv0_53\0\bv1_53\0\bv2_53\0\bv3_53\0\bv4_53\0\bv5_53\0\bv6_53\0\kvr0_53\0\kvr1_53\0\kvr2_53\0\kvr3_53\0\kvr4_53\0\kvr5_53\0\kvr6_53\0\tk0_53\0\tk1_53\0\tk2_53\88\tk3_53\0\tk4_53\0\tk5_53\0\tk6_53\0\kk0_53\0\kk1_53\0\kk2_53\1\kk3_53\0\kk4_53\0\kk5_53\0\kk6_53\0\dk0_53\0\dk1_53\0\dk2_53\0\dk3_53\0\dk4_53\0\dk5_53\0\dk6_53\0\tw0_53\0\tw1_53\0\tw2_53\0\tw3_53\0\tw4_53\0\tw5_53\0\tw6_53\0\tw7_53\0\tw8_53\78\te0_53\0\te1_53\0\te3_53\9\te2_53\0\te4_53\0\te5_53\0\te6_53\0\te7_53\0\te8_53\0\kw0_53\0\kw1_53\0\kw2_53\0\kw3_53\0\kw4_53\0\kw5_53\0\kw6_53\0\kw7_53\0\kw8_53\0\ke0_53\0\ke1_53\0\ke3_53\1\ke2_53\0\ke4_53\0\ke5_53\0\bw0_53\0\bw1_53\0\bw2_53\0\bw3_53\0\bw4_53\0\bw5_53\0\bw6_53\0\bw7_53\0\bw8_53\0\be0_53\0\be1_53\0\be3_53\0\be2_53\0\be4_53\0\be5_53\0\be8_53\0\be9_53\0\de6_53\0\de7_53\0\de8_53\0\sw0_53\0\sw1_53\0\sw2_53\0\sw3_53\0\sw4_53\0\sw5_53\0\sw6_53\0\sw7_53\0\sw8_53\0\se0_53\0\se1_53\0\se2_53\0\se3_53\3\se4_53\0\se5_53\0\hw0_53\0\hw1_53\0\hw2_53\0\hw3_53\0\hw4_53\0\hw5_53\0\hw6_53\0\hw7_53\0\hw8_53\0\he0_53\0\he1_53\0\he2_53\0\he3_53\2\he4_53\0\he5_53\0\pID_54\28999990\name_54\J. Newton\t_54\2\a_54\0\ctime_54\88\c_54\1\ip_54\127.0.0.1\ai_54\1\rs_54\0\cs_54\0\ss_54\0\ts_54\0\kills_54\0\deaths_54\0\cpc_54\0\cpa_54\0\cpd_54\0\ka_54\0\he_54\0\rev_54\0\rsp_54\0\rep_54\0\tre_54\0\drs_54\0\tmkl_54\0\tmdg_54\0\tmvd_54\0\su_54\0\ks_54\0\ds_54\0\rank_54\0\ban_54\0\kck_54\0\tco_54\0\tsl_54\88\tsm_54\0\tlw_54\0\ta0_54\88\ta1_54\0\ta2_54\0\ta3_54\0\ta4_54\0\ta5_54\0\ta6_54\0\ta7_54\0\ta8_54\0\ta9_54\0\ta10_54\0\ta11_54\0\ta12_54\0\ta13_54\0\tv0_54\0\tv1_54\0\tv2_54\0\tv3_54\0\tv4_54\0\tv5_54\0\tv6_54\0\tvp_54\0\kv0_54\0\kv1_54\0\kv2_54\0\kv3_54\0\kv4_54\0\kv5_54\0\kv6_54\0\bv0_54\0\bv1_54\0\bv2_54\0\bv3_54\0\bv4_54\0\bv5_54\0\bv6_54\0\kvr0_54\0\kvr1_54\0\kvr2_54\0\kvr3_54\0\kvr4_54\0\kvr5_54\0\kvr6_54\0\tk0_54\0\tk1_54\0\tk2_54\0\tk3_54\0\tk4_54\0\tk5_54\87\tk6_54\0\kk0_54\0\kk1_54\0\kk2_54\0\kk3_54\0\kk4_54\0\kk5_54\0\kk6_54\0\dk0_54\0\dk1_54\0\dk2_54\0\dk3_54\0\dk4_54\0\dk5_54\0\dk6_54\0\tw0_54\0\tw1_54\0\tw2_54\0\tw3_54\82\tw4_54\0\tw5_54\0\tw6_54\0\tw7_54\0\tw8_54\0\te0_54\0\te1_54\0\te3_54\5\te2_54\0\te4_54\0\te5_54\0\te6_54\0\te7_54\0\te8_54\0\kw0_54\0\kw1_54\0\kw2_54\0\kw3_54\0\kw4_54\0\kw5_54\0\kw6_54\0\kw7_54\0\kw8_54\0\ke0_54\0\ke1_54\0\ke3_54\0\ke2_54\0\ke4_54\0\ke5_54\0\bw0_54\0\bw1_54\0\bw2_54\0\bw3_54\0\bw4_54\0\bw5_54\0\bw6_54\0\bw7_54\0\bw8_54\0\be0_54\0\be1_54\0\be3_54\0\be2_54\0\be4_54\0\be5_54\0\be8_54\0\be9_54\0\de6_54\0\de7_54\0\de8_54\0\sw0_54\0\sw1_54\0\sw2_54\0\sw3_54\71\sw4_54\0\sw5_54\0\sw6_54\0\sw7_54\0\sw8_54\0\se0_54\0\se1_54\0\se2_54\0\se3_54\0\se4_54\0\se5_54\0\hw0_54\0\hw1_54\0\hw2_54\0\hw3_54\0\hw4_54\0\hw5_54\0\hw6_54\0\hw7_54\0\hw8_54\0\he0_54\0\he1_54\0\he2_54\0\he3_54\0\he4_54\0\he5_54\0\pID_55\28999998\name_55\F. Liliegren\t_55\2\a_55\0\ctime_55\88\c_55\1\ip_55\127.0.0.1\ai_55\1\rs_55\1\cs_55\0\ss_55\0\ts_55\1\kills_55\0\deaths_55\0\cpc_55\0\cpa_55\0\cpd_55\0\ka_55\1\he_55\0\rev_55\0\rsp_55\0\rep_55\0\tre_55\0\drs_55\0\tmkl_55\0\tmdg_55\0\tmvd_55\0\su_55\0\ks_55\0\ds_55\0\rank_55\0\ban_55\0\kck_55\0\tco_55\0\tsl_55\0\tsm_55\88\tlw_55\0\ta0_55\88\ta1_55\0\ta2_55\0\ta3_55\0\ta4_55\0\ta5_55\0\ta6_55\0\ta7_55\0\ta8_55\0\ta9_55\0\ta10_55\0\ta11_55\0\ta12_55\0\ta13_55\0\tv0_55\0\tv1_55\0\tv2_55\0\tv3_55\0\tv4_55\0\tv5_55\0\tv6_55\0\tvp_55\0\kv0_55\0\kv1_55\0\kv2_55\0\kv3_55\0\kv4_55\0\kv5_55\0\kv6_55\0\bv0_55\0\bv1_55\0\bv2_55\0\bv3_55\0\bv4_55\0\bv5_55\0\bv6_55\0\kvr0_55\0\kvr1_55\0\kvr2_55\0\kvr3_55\0\kvr4_55\0\kvr5_55\0\kvr6_55\0\tk0_55\0\tk1_55\0\tk2_55\0\tk3_55\0\tk4_55\0\tk5_55\0\tk6_55\88\kk0_55\0\kk1_55\0\kk2_55\0\kk3_55\0\kk4_55\0\kk5_55\0\kk6_55\0\dk0_55\0\dk1_55\0\dk2_55\0\dk3_55\0\dk4_55\0\dk5_55\0\dk6_55\0\tw0_55\0\tw1_55\0\tw2_55\0\tw3_55\0\tw4_55\37\tw5_55\4\tw6_55\0\tw7_55\0\tw8_55\0\te0_55\0\te1_55\0\te3_55\46\te2_55\0\te4_55\0\te5_55\0\te6_55\0\te7_55\0\te8_55\0\kw0_55\0\kw1_55\0\kw2_55\0\kw3_55\0\kw4_55\0\kw5_55\0\kw6_55\0\kw7_55\0\kw8_55\0\ke0_55\0\ke1_55\0\ke3_55\0\ke2_55\0\ke4_55\0\ke5_55\0\bw0_55\0\bw1_55\0\bw2_55\0\bw3_55\0\bw4_55\0\bw5_55\0\bw6_55\0\bw7_55\0\bw8_55\0\be0_55\0\be1_55\0\be3_55\0\be2_55\0\be4_55\0\be5_55\0\be8_55\0\be9_55\0\de6_55\0\de7_55\0\de8_55\0\sw0_55\0\sw1_55\0\sw2_55\0\sw3_55\0\sw4_55\0\sw5_55\0\sw6_55\0\sw7_55\0\sw8_55\0\se0_55\0\se1_55\0\se2_55\0\se3_55\4\se4_55\0\se5_55\0\hw0_55\0\hw1_55\0\hw2_55\0\hw3_55\0\hw4_55\0\hw5_55\0\hw6_55\0\hw7_55\0\hw8_55\0\he0_55\0\he1_55\0\he2_55\0\he3_55\2\he4_55\0\he5_55\0\pID_56\28999959\name_56\J. Norberg\t_56\2\a_56\0\ctime_56\88\c_56\1\ip_56\127.0.0.1\ai_56\1\rs_56\4\cs_56\0\ss_56\2\ts_56\2\kills_56\1\deaths_56\0\cpc_56\0\cpa_56\0\cpd_56\0\ka_56\0\he_56\0\rev_56\1\rsp_56\0\rep_56\0\tre_56\0\drs_56\0\tmkl_56\0\tmdg_56\0\tmvd_56\0\su_56\0\ks_56\1\ds_56\0\rank_56\0\ban_56\0\kck_56\0\tco_56\0\tsl_56\0\tsm_56\88\tlw_56\0\ta0_56\88\ta1_56\0\ta2_56\0\ta3_56\0\ta4_56\0\ta5_56\0\ta6_56\0\ta7_56\0\ta8_56\0\ta9_56\0\ta10_56\0\ta11_56\0\ta12_56\0\ta13_56\0\mvns_56\28999949\mvks_56\1\tv0_56\0\tv1_56\0\tv2_56\0\tv3_56\0\tv4_56\0\tv5_56\0\tv6_56\0\tvp_56\0\kv0_56\0\kv1_56\0\kv2_56\0\kv3_56\0\kv4_56\0\kv5_56\0\kv6_56\0\bv0_56\0\bv1_56\0\bv2_56\0\bv3_56\0\bv4_56\0\bv5_56\0\bv6_56\0\kvr0_56\0\kvr1_56\0\kvr2_56\0\kvr3_56\0\kvr4_56\0\kvr5_56\0\kvr6_56\0\tk0_56\0\tk1_56\0\tk2_56\0\tk3_56\88\tk4_56\0\tk5_56\0\tk6_56\0\kk0_56\0\kk1_56\0\kk2_56\0\kk3_56\1\kk4_56\0\kk5_56\0\kk6_56\0\dk0_56\0\dk1_56\0\dk2_56\0\dk3_56\0\dk4_56\0\dk5_56\0\dk6_56\0\tw0_56\65\tw1_56\0\tw2_56\0\tw3_56\0\tw4_56\0\tw5_56\0\tw6_56\0\tw7_56\0\tw8_56\0\te0_56\0\te1_56\0\te3_56\13\te2_56\0\te4_56\9\te5_56\0\te6_56\0\te7_56\0\te8_56\0\kw0_56\1\kw1_56\0\kw2_56\0\kw3_56\0\kw4_56\0\kw5_56\0\kw6_56\0\kw7_56\0\kw8_56\0\ke0_56\0\ke1_56\0\ke3_56\0\ke2_56\0\ke4_56\0\ke5_56\0\bw0_56\0\bw1_56\0\bw2_56\0\bw3_56\0\bw4_56\0\bw5_56\0\bw6_56\0\bw7_56\0\bw8_56\0\be0_56\0\be1_56\0\be3_56\0\be2_56\0\be4_56\0\be5_56\0\be8_56\0\be9_56\0\de6_56\0\de7_56\0\de8_56\0\sw0_56\30\sw1_56\0\sw2_56\0\sw3_56\0\sw4_56\0\sw5_56\0\sw6_56\0\sw7_56\0\sw8_56\0\se0_56\0\se1_56\0\se2_56\0\se3_56\0\se4_56\1\se5_56\0\hw0_56\1\hw1_56\0\hw2_56\0\hw3_56\0\hw4_56\0\hw5_56\0\hw6_56\0\hw7_56\0\hw8_56\0\he0_56\0\he1_56\0\he2_56\0\he3_56\0\he4_56\1\he5_56\0\pID_57\28999977\name_57\K. Hoang\t_57\2\a_57\0\ctime_57\88\c_57\1\ip_57\127.0.0.1\ai_57\1\rs_57\0\cs_57\0\ss_57\0\ts_57\0\kills_57\0\deaths_57\0\cpc_57\0\cpa_57\0\cpd_57\0\ka_57\0\he_57\0\rev_57\0\rsp_57\0\rep_57\0\tre_57\0\drs_57\0\tmkl_57\0\tmdg_57\0\tmvd_57\0\su_57\0\ks_57\0\ds_57\0\rank_57\0\ban_57\0\kck_57\0\tco_57\0\tsl_57\0\tsm_57\88\tlw_57\0\ta0_57\88\ta1_57\0\ta2_57\0\ta3_57\0\ta4_57\0\ta5_57\0\ta6_57\0\ta7_57\0\ta8_57\0\ta9_57\0\ta10_57\0\ta11_57\0\ta12_57\0\ta13_57\0\tv0_57\0\tv1_57\0\tv2_57\0\tv3_57\0\tv4_57\25\tv5_57\0\tv6_57\0\tvp_57\0\kv0_57\0\kv1_57\0\kv2_57\0\kv3_57\0\kv4_57\0\kv5_57\0\kv6_57\0\bv0_57\0\bv1_57\0\bv2_57\0\bv3_57\0\bv4_57\0\bv5_57\0\bv6_57\0\kvr0_57\0\kvr1_57\0\kvr2_57\0\kvr3_57\0\kvr4_57\0\kvr5_57\0\kvr6_57\0\tk0_57\0\tk1_57\0\tk2_57\0\tk3_57\0\tk4_57\0\tk5_57\88\tk6_57\0\kk0_57\0\kk1_57\0\kk2_57\0\kk3_57\0\kk4_57\0\kk5_57\0\kk6_57\0\dk0_57\0\dk1_57\0\dk2_57\0\dk3_57\0\dk4_57\0\dk5_57\0\dk6_57\0\tw0_57\0\tw1_57\0\tw2_57\0\tw3_57\62\tw4_57\0\tw5_57\0\tw6_57\0\tw7_57\0\tw8_57\0\te0_57\0\te1_57\0\te3_57\0\te2_57\0\te4_57\0\te5_57\0\te6_57\0\te7_57\0\te8_57\0\kw0_57\0\kw1_57\0\kw2_57\0\kw3_57\0\kw4_57\0\kw5_57\0\kw6_57\0\kw7_57\0\kw8_57\0\ke0_57\0\ke1_57\0\ke3_57\0\ke2_57\0\ke4_57\0\ke5_57\0\bw0_57\0\bw1_57\0\bw2_57\0\bw3_57\0\bw4_57\0\bw5_57\0\bw6_57\0\bw7_57\0\bw8_57\0\be0_57\0\be1_57\0\be3_57\0\be2_57\0\be4_57\0\be5_57\0\be8_57\0\be9_57\0\de6_57\0\de7_57\0\de8_57\0\sw0_57\0\sw1_57\0\sw2_57\0\sw3_57\0\sw4_57\0\sw5_57\0\sw6_57\0\sw7_57\0\sw8_57\0\se0_57\0\se1_57\0\se2_57\0\se3_57\0\se4_57\0\se5_57\0\hw0_57\0\hw1_57\0\hw2_57\0\hw3_57\0\hw4_57\0\hw5_57\0\hw6_57\0\hw7_57\0\hw8_57\0\he0_57\0\he1_57\0\he2_57\0\he3_57\0\he4_57\0\he5_57\0\pID_58\28999918\name_58\W. Young\t_58\2\a_58\0\ctime_58\73\c_58\1\ip_58\127.0.0.1\ai_58\1\rs_58\2\cs_58\0\ss_58\2\ts_58\0\kills_58\1\deaths_58\1\cpc_58\0\cpa_58\0\cpd_58\0\ka_58\0\he_58\0\rev_58\0\rsp_58\0\rep_58\0\tre_58\0\drs_58\0\tmkl_58\0\tmdg_58\0\tmvd_58\0\su_58\0\ks_58\1\ds_58\1\rank_58\0\ban_58\0\kck_58\0\tco_58\0\tsl_58\0\tsm_58\73\tlw_58\0\ta0_58\73\ta1_58\0\ta2_58\0\ta3_58\0\ta4_58\0\ta5_58\0\ta6_58\0\ta7_58\0\ta8_58\0\ta9_58\0\ta10_58\0\ta11_58\0\ta12_58\0\ta13_58\0\mvns_58\100000001\mvks_58\1\tv0_58\0\tv1_58\0\tv2_58\0\tv3_58\0\tv4_58\0\tv5_58\0\tv6_58\0\tvp_58\0\kv0_58\0\kv1_58\0\kv2_58\0\kv3_58\0\kv4_58\0\kv5_58\0\kv6_58\0\bv0_58\0\bv1_58\0\bv2_58\0\bv3_58\0\bv4_58\0\bv5_58\0\bv6_58\0\kvr0_58\0\kvr1_58\0\kvr2_58\0\kvr3_58\0\kvr4_58\0\kvr5_58\0\kvr6_58\0\tk0_58\31\tk1_58\0\tk2_58\0\tk3_58\0\tk4_58\0\tk5_58\0\tk6_58\34\kk0_58\1\kk1_58\0\kk2_58\0\kk3_58\0\kk4_58\0\kk5_58\0\kk6_58\0\dk0_58\0\dk1_58\0\dk2_58\0\dk3_58\0\dk4_58\0\dk5_58\0\dk6_58\1\tw0_58\0\tw1_58\0\tw2_58\0\tw3_58\0\tw4_58\21\tw5_58\0\tw6_58\7\tw7_58\24\tw8_58\0\te0_58\0\te1_58\0\te3_58\13\te2_58\0\te4_58\0\te5_58\0\te6_58\0\te7_58\0\te8_58\0\kw0_58\0\kw1_58\0\kw2_58\0\kw3_58\0\kw4_58\0\kw5_58\0\kw6_58\1\kw7_58\0\kw8_58\0\ke0_58\0\ke1_58\0\ke3_58\0\ke2_58\0\ke4_58\0\ke5_58\0\bw0_58\0\bw1_58\0\bw2_58\0\bw3_58\0\bw4_58\0\bw5_58\0\bw6_58\0\bw7_58\0\bw8_58\0\be0_58\0\be1_58\0\be3_58\1\be2_58\0\be4_58\0\be5_58\0\be8_58\0\be9_58\0\de6_58\0\de7_58\0\de8_58\0\sw0_58\0\sw1_58\0\sw2_58\0\sw3_58\0\sw4_58\0\sw5_58\0\sw6_58\2\sw7_58\29\sw8_58\0\se0_58\0\se1_58\0\se2_58\0\se3_58\0\se4_58\0\se5_58\0\hw0_58\0\hw1_58\0\hw2_58\0\hw3_58\0\hw4_58\0\hw5_58\0\hw6_58\1\hw7_58\3\hw8_58\0\he0_58\0\he1_58\0\he2_58\0\he3_58\0\he4_58\0\he5_58\0\pID_59\28999943\name_59\J. Lord\t_59\2\a_59\0\ctime_59\88\c_59\1\ip_59\127.0.0.1\ai_59\1\rs_59\0\cs_59\0\ss_59\0\ts_59\0\kills_59\0\deaths_59\0\cpc_59\0\cpa_59\0\cpd_59\0\ka_59\0\he_59\0\rev_59\0\rsp_59\0\rep_59\0\tre_59\0\drs_59\0\tmkl_59\0\tmdg_59\0\tmvd_59\0\su_59\0\ks_59\0\ds_59\0\rank_59\0\ban_59\0\kck_59\0\tco_59\0\tsl_59\0\tsm_59\88\tlw_59\0\ta0_59\88\ta1_59\0\ta2_59\0\ta3_59\0\ta4_59\0\ta5_59\0\ta6_59\0\ta7_59\0\ta8_59\0\ta9_59\0\ta10_59\0\ta11_59\0\ta12_59\0\ta13_59\0\tv0_59\0\tv1_59\0\tv2_59\0\tv3_59\0\tv4_59\0\tv5_59\0\tv6_59\0\tvp_59\0\kv0_59\0\kv1_59\0\kv2_59\0\kv3_59\0\kv4_59\0\kv5_59\0\kv6_59\0\bv0_59\0\bv1_59\0\bv2_59\0\bv3_59\0\bv4_59\0\bv5_59\0\bv6_59\0\kvr0_59\0\kvr1_59\0\kvr2_59\0\kvr3_59\0\kvr4_59\0\kvr5_59\0\kvr6_59\0\tk0_59\0\tk1_59\0\tk2_59\0\tk3_59\0\tk4_59\0\tk5_59\82\tk6_59\0\kk0_59\0\kk1_59\0\kk2_59\0\kk3_59\0\kk4_59\0\kk5_59\0\kk6_59\0\dk0_59\0\dk1_59\0\dk2_59\0\dk3_59\0\dk4_59\0\dk5_59\0\dk6_59\0\tw0_59\0\tw1_59\0\tw2_59\0\tw3_59\82\tw4_59\0\tw5_59\0\tw6_59\0\tw7_59\0\tw8_59\0\te0_59\0\te1_59\0\te3_59\0\te2_59\0\te4_59\0\te5_59\0\te6_59\0\te7_59\0\te8_59\0\kw0_59\0\kw1_59\0\kw2_59\0\kw3_59\0\kw4_59\0\kw5_59\0\kw6_59\0\kw7_59\0\kw8_59\0\ke0_59\0\ke1_59\0\ke3_59\0\ke2_59\0\ke4_59\0\ke5_59\0\bw0_59\0\bw1_59\0\bw2_59\0\bw3_59\0\bw4_59\0\bw5_59\0\bw6_59\0\bw7_59\0\bw8_59\0\be0_59\0\be1_59\0\be3_59\0\be2_59\0\be4_59\0\be5_59\0\be8_59\0\be9_59\0\de6_59\0\de7_59\0\de8_59\0\sw0_59\0\sw1_59\0\sw2_59\0\sw3_59\0\sw4_59\0\sw5_59\0\sw6_59\0\sw7_59\0\sw8_59\0\se0_59\0\se1_59\0\se2_59\0\se3_59\0\se4_59\0\se5_59\0\hw0_59\0\hw1_59\0\hw2_59\0\hw3_59\0\hw4_59\0\hw5_59\0\hw6_59\0\hw7_59\0\hw8_59\0\he0_59\0\he1_59\0\he2_59\0\he3_59\0\he4_59\0\he5_59\0\pID_60\28999896\name_60\J. Persson\t_60\2\a_60\0\ctime_60\88\c_60\1\ip_60\127.0.0.1\ai_60\1\rs_60\0\cs_60\0\ss_60\0\ts_60\0\kills_60\0\deaths_60\0\cpc_60\0\cpa_60\0\cpd_60\0\ka_60\0\he_60\0\rev_60\0\rsp_60\0\rep_60\0\tre_60\0\drs_60\0\tmkl_60\0\tmdg_60\0\tmvd_60\0\su_60\0\ks_60\0\ds_60\0\rank_60\0\ban_60\0\kck_60\0\tco_60\0\tsl_60\0\tsm_60\88\tlw_60\0\ta0_60\88\ta1_60\0\ta2_60\0\ta3_60\0\ta4_60\0\ta5_60\0\ta6_60\0\ta7_60\0\ta8_60\0\ta9_60\0\ta10_60\0\ta11_60\0\ta12_60\0\ta13_60\0\tv0_60\0\tv1_60\0\tv2_60\0\tv3_60\0\tv4_60\0\tv5_60\0\tv6_60\0\tvp_60\0\kv0_60\0\kv1_60\0\kv2_60\0\kv3_60\0\kv4_60\0\kv5_60\0\kv6_60\0\bv0_60\0\bv1_60\0\bv2_60\0\bv3_60\0\bv4_60\0\bv5_60\0\bv6_60\0\kvr0_60\0\kvr1_60\0\kvr2_60\0\kvr3_60\0\kvr4_60\0\kvr5_60\0\kvr6_60\0\tk0_60\0\tk1_60\0\tk2_60\0\tk3_60\0\tk4_60\0\tk5_60\88\tk6_60\0\kk0_60\0\kk1_60\0\kk2_60\0\kk3_60\0\kk4_60\0\kk5_60\0\kk6_60\0\dk0_60\0\dk1_60\0\dk2_60\0\dk3_60\0\dk4_60\0\dk5_60\0\dk6_60\0\tw0_60\0\tw1_60\0\tw2_60\0\tw3_60\82\tw4_60\0\tw5_60\0\tw6_60\0\tw7_60\0\tw8_60\0\te0_60\0\te1_60\0\te3_60\5\te2_60\0\te4_60\0\te5_60\0\te6_60\0\te7_60\0\te8_60\0\kw0_60\0\kw1_60\0\kw2_60\0\kw3_60\0\kw4_60\0\kw5_60\0\kw6_60\0\kw7_60\0\kw8_60\0\ke0_60\0\ke1_60\0\ke3_60\0\ke2_60\0\ke4_60\0\ke5_60\0\bw0_60\0\bw1_60\0\bw2_60\0\bw3_60\0\bw4_60\0\bw5_60\0\bw6_60\0\bw7_60\0\bw8_60\0\be0_60\0\be1_60\0\be3_60\0\be2_60\0\be4_60\0\be5_60\0\be8_60\0\be9_60\0\de6_60\0\de7_60\0\de8_60\0\sw0_60\0\sw1_60\0\sw2_60\0\sw3_60\18\sw4_60\0\sw5_60\0\sw6_60\0\sw7_60\0\sw8_60\0\se0_60\0\se1_60\0\se2_60\0\se3_60\0\se4_60\0\se5_60\0\hw0_60\0\hw1_60\0\hw2_60\0\hw3_60\0\hw4_60\0\hw5_60\0\hw6_60\0\hw7_60\0\hw8_60\0\he0_60\0\he1_60\0\he2_60\0\he3_60\0\he4_60\0\he5_60\0\pID_61\28999876\name_61\M. Hart\t_61\2\a_61\0\ctime_61\88\c_61\1\ip_61\127.0.0.1\ai_61\1\rs_61\0\cs_61\0\ss_61\0\ts_61\0\kills_61\0\deaths_61\0\cpc_61\0\cpa_61\0\cpd_61\0\ka_61\0\he_61\0\rev_61\0\rsp_61\0\rep_61\0\tre_61\0\drs_61\0\tmkl_61\0\tmdg_61\0\tmvd_61\0\su_61\0\ks_61\0\ds_61\0\rank_61\0\ban_61\0\kck_61\0\tco_61\0\tsl_61\0\tsm_61\88\tlw_61\0\ta0_61\88\ta1_61\0\ta2_61\0\ta3_61\0\ta4_61\0\ta5_61\0\ta6_61\0\ta7_61\0\ta8_61\0\ta9_61\0\ta10_61\0\ta11_61\0\ta12_61\0\ta13_61\0\tv0_61\0\tv1_61\0\tv2_61\0\tv3_61\0\tv4_61\0\tv5_61\0\tv6_61\0\tvp_61\0\kv0_61\0\kv1_61\0\kv2_61\0\kv3_61\0\kv4_61\0\kv5_61\0\kv6_61\0\bv0_61\0\bv1_61\0\bv2_61\0\bv3_61\0\bv4_61\0\bv5_61\0\bv6_61\0\kvr0_61\0\kvr1_61\0\kvr2_61\0\kvr3_61\0\kvr4_61\0\kvr5_61\0\kvr6_61\0\tk0_61\88\tk1_61\0\tk2_61\0\tk3_61\0\tk4_61\0\tk5_61\0\tk6_61\0\kk0_61\0\kk1_61\0\kk2_61\0\kk3_61\0\kk4_61\0\kk5_61\0\kk6_61\0\dk0_61\0\dk1_61\0\dk2_61\0\dk3_61\0\dk4_61\0\dk5_61\0\dk6_61\0\tw0_61\0\tw1_61\0\tw2_61\0\tw3_61\0\tw4_61\0\tw5_61\4\tw6_61\0\tw7_61\83\tw8_61\0\te0_61\0\te1_61\0\te3_61\0\te2_61\0\te4_61\0\te5_61\0\te6_61\0\te7_61\0\te8_61\0\kw0_61\0\kw1_61\0\kw2_61\0\kw3_61\0\kw4_61\0\kw5_61\0\kw6_61\0\kw7_61\0\kw8_61\0\ke0_61\0\ke1_61\0\ke3_61\0\ke2_61\0\ke4_61\0\ke5_61\0\bw0_61\0\bw1_61\0\bw2_61\0\bw3_61\0\bw4_61\0\bw5_61\0\bw6_61\0\bw7_61\0\bw8_61\0\be0_61\0\be1_61\0\be3_61\0\be2_61\0\be4_61\0\be5_61\0\be8_61\0\be9_61\0\de6_61\0\de7_61\0\de8_61\0\sw0_61\0\sw1_61\0\sw2_61\0\sw3_61\0\sw4_61\0\sw5_61\15\sw6_61\0\sw7_61\30\sw8_61\0\se0_61\0\se1_61\0\se2_61\0\se3_61\0\se4_61\0\se5_61\0\hw0_61\0\hw1_61\0\hw2_61\0\hw3_61\0\hw4_61\0\hw5_61\1\hw6_61\0\hw7_61\1\hw8_61\0\he0_61\0\he1_61\0\he2_61\0\he3_61\0\he4_61\0\he5_61\0\pID_62\28999905\name_62\M. Le\t_62\2\a_62\0\ctime_62\88\c_62\1\ip_62\127.0.0.1\ai_62\1\rs_62\0\cs_62\0\ss_62\0\ts_62\0\kills_62\0\deaths_62\0\cpc_62\0\cpa_62\0\cpd_62\0\ka_62\0\he_62\0\rev_62\0\rsp_62\0\rep_62\0\tre_62\0\drs_62\0\tmkl_62\0\tmdg_62\0\tmvd_62\0\su_62\0\ks_62\0\ds_62\0\rank_62\0\ban_62\0\kck_62\0\tco_62\0\tsl_62\0\tsm_62\88\tlw_62\0\ta0_62\88\ta1_62\0\ta2_62\0\ta3_62\0\ta4_62\0\ta5_62\0\ta6_62\0\ta7_62\0\ta8_62\0\ta9_62\0\ta10_62\0\ta11_62\0\ta12_62\0\ta13_62\0\tv0_62\0\tv1_62\0\tv2_62\0\tv3_62\0\tv4_62\0\tv5_62\0\tv6_62\0\tvp_62\0\kv0_62\0\kv1_62\0\kv2_62\0\kv3_62\0\kv4_62\0\kv5_62\0\kv6_62\0\bv0_62\0\bv1_62\0\bv2_62\0\bv3_62\0\bv4_62\0\bv5_62\0\bv6_62\0\kvr0_62\0\kvr1_62\0\kvr2_62\0\kvr3_62\0\kvr4_62\0\kvr5_62\0\kvr6_62\0\tk0_62\0\tk1_62\0\tk2_62\0\tk3_62\0\tk4_62\0\tk5_62\88\tk6_62\0\kk0_62\0\kk1_62\0\kk2_62\0\kk3_62\0\kk4_62\0\kk5_62\0\kk6_62\0\dk0_62\0\dk1_62\0\dk2_62\0\dk3_62\0\dk4_62\0\dk5_62\0\dk6_62\0\tw0_62\0\tw1_62\0\tw2_62\0\tw3_62\64\tw4_62\0\tw5_62\0\tw6_62\0\tw7_62\0\tw8_62\0\te0_62\0\te1_62\0\te3_62\24\te2_62\0\te4_62\0\te5_62\0\te6_62\0\te7_62\0\te8_62\0\kw0_62\0\kw1_62\0\kw2_62\0\kw3_62\0\kw4_62\0\kw5_62\0\kw6_62\0\kw7_62\0\kw8_62\0\ke0_62\0\ke1_62\0\ke3_62\0\ke2_62\0\ke4_62\0\ke5_62\0\bw0_62\0\bw1_62\0\bw2_62\0\bw3_62\0\bw4_62\0\bw5_62\0\bw6_62\0\bw7_62\0\bw8_62\0\be0_62\0\be1_62\0\be3_62\0\be2_62\0\be4_62\0\be5_62\0\be8_62\0\be9_62\0\de6_62\0\de7_62\0\de8_62\0\sw0_62\0\sw1_62\0\sw2_62\0\sw3_62\1\sw4_62\0\sw5_62\0\sw6_62\0\sw7_62\0\sw8_62\0\se0_62\0\se1_62\0\se2_62\0\se3_62\1\se4_62\0\se5_62\0\hw0_62\0\hw1_62\0\hw2_62\0\hw3_62\0\hw4_62\0\hw5_62\0\hw6_62\0\hw7_62\0\hw8_62\0\he0_62\0\he1_62\0\he2_62\0\he3_62\1\he4_62\0\he5_62\0\pID_63\100000001\name_63\ test\t_63\1\a_63\2\ctime_63\78\c_63\1\ip_63\192.168.122.3\ai_63\0\rs_63\26\cs_63\0\ss_63\28\ts_63\0\kills_63\14\deaths_63\1\cpc_63\0\cpa_63\0\cpd_63\0\ka_63\2\he_63\0\rev_63\0\rsp_63\0\rep_63\0\tre_63\0\drs_63\0\tmkl_63\1\tmdg_63\0\tmvd_63\0\su_63\0\ks_63\14\ds_63\1\rank_63\0\ban_63\0\kck_63\0\tco_63\0\tsl_63\0\tsm_63\0\tlw_63\78\ta0_63\0\ta1_63\0\ta2_63\78\ta3_63\0\ta4_63\0\ta5_63\0\ta6_63\0\ta7_63\0\ta8_63\0\ta9_63\0\ta10_63\0\ta11_63\0\ta12_63\0\ta13_63\0\mvns_63\28999893\mvks_63\1\mvns_63\28999950\mvks_63\1\mvns_63\28999924\mvks_63\1\mvns_63\28999931\mvks_63\2\mvns_63\28999929\mvks_63\1\mvns_63\28999999\mvks_63\1\mvns_63\28999881\mvks_63\1\mvns_63\28999897\mvks_63\1\mvns_63\28999935\mvks_63\1\mvns_63\28999918\mvks_63\2\mvns_63\28999993\mvks_63\1\mvns_63\28999962\mvks_63\1\erg_63\1\tv0_63\68\tv1_63\0\tv2_63\0\tv3_63\0\tv4_63\0\tv5_63\0\tv6_63\0\tvp_63\0\kv0_63\14\kv1_63\0\kv2_63\0\kv3_63\0\kv4_63\0\kv5_63\0\kv6_63\0\bv0_63\1\bv1_63\0\bv2_63\0\bv3_63\0\bv4_63\0\bv5_63\0\bv6_63\0\kvr0_63\1\kvr1_63\0\kvr2_63\0\kvr3_63\0\kvr4_63\0\kvr5_63\0\kvr6_63\0\tk0_63\0\tk1_63\78\tk2_63\0\tk3_63\0\tk4_63\0\tk5_63\0\tk6_63\0\kk0_63\0\kk1_63\14\kk2_63\0\kk3_63\0\kk4_63\0\kk5_63\0\kk6_63\0\dk0_63\0\dk1_63\1\dk2_63\0\dk3_63\0\dk4_63\0\dk5_63\0\dk6_63\0\tw0_63\9\tw1_63\0\tw2_63\0\tw3_63\0\tw4_63\0\tw5_63\0\tw6_63\0\tw7_63\0\tw8_63\0\te0_63\0\te1_63\0\te3_63\0\te2_63\0\te4_63\0\te5_63\0\te6_63\0\te7_63\0\te8_63\0\kw0_63\0\kw1_63\0\kw2_63\0\kw3_63\0\kw4_63\0\kw5_63\0\kw6_63\0\kw7_63\0\kw8_63\0\ke0_63\0\ke1_63\0\ke3_63\0\ke2_63\0\ke4_63\0\ke5_63\0\bw0_63\0\bw1_63\0\bw2_63\0\bw3_63\0\bw4_63\0\bw5_63\0\bw6_63\0\bw7_63\0\bw8_63\0\be0_63\0\be1_63\0\be3_63\0\be2_63\0\be4_63\0\be5_63\0\be8_63\0\be9_63\0\de6_63\0\de7_63\0\de8_63\0\sw0_63\0\sw1_63\0\sw2_63\0\sw3_63\0\sw4_63\0\sw5_63\0\sw6_63\0\sw7_63\0\sw8_63\0\se0_63\0\se1_63\0\se2_63\0\se3_63\0\se4_63\0\se5_63\0\hw0_63\0\hw1_63\0\hw2_63\0\hw3_63\0\hw4_63\0\hw5_63\0\hw6_63\0\hw7_63\0\hw8_63\0\he0_63\0\he1_63\0\he2_63\0\he3_63\0\he4_63\0\he5_63\0\EOF\1 \ No newline at end of file diff --git a/test/snapshots/-test-snapshot.txt b/test/snapshots/-test-snapshot.txt new file mode 100644 index 00000000..021e34bf --- /dev/null +++ b/test/snapshots/-test-snapshot.txt @@ -0,0 +1 @@ +TST\test_server\queryport\29900\mapname\test_map\mapid\999\mapstart\1157264950.7\mapend\1157266995.57\win\1\gm\0\v\bf2\pc\1\rwa\2\ra1\0\rs1\25\ra2\2\rs2\0\pID_0\999\name_0\Test Player\t_0\2\a_0\0\ctime_0\1559\c_0\1\ip_0\0\ai_0\0\rs_0\24\cs_0\0\ss_0\18\ts_0\6\kills_0\9\deaths_0\17\cpc_0\0\cpn_0\1\cpa_0\0\cpna_0\0\cpd_0\0\ka_0\0\he_0\0\rev_0\0\rsp_0\0\rep_0\0\tre_0\0\drs_0\0\dra_0\4\pa_0\0\tmkl_0\0\tmdg_0\0\tmvd_0\0\su_0\0\ks_0\6\ds_0\6\rank_0\3\ban_0\0\kck_0\0\tco_0\0\tsl_0\1559\tsm_0\0\tlw_0\0\ta0_0\1559\ta1_0\0\ta2_0\0\ta3_0\0\ta4_0\0\ta5_0\0\ta6_0\0\ta7_0\0\ta8_0\0\ta9_0\0\ta10_0\0\ta11_0\0\ta12_0\0\ta13_0\0\mvns_0\29000037\mvks_0\1\mvns_0\29000113\mvks_0\1\mvns_0\29000069\mvks_0\1\mvns_0\29000081\mvks_0\2\mvns_0\29000108\mvks_0\1\mvns_0\29000080\mvks_0\1\mvns_0\29000089\mvks_0\1\mvns_0\29000041\mvks_0\1\tv0_0\278\tv1_0\0\tv2_0\0\tv3_0\532\tv4_0\227\tv5_0\0\tv6_0\0\tvp_0\17\kv0_0\5\kv1_0\0\kv2_0\0\kv3_0\0\kv4_0\0\kv5_0\0\kv6_0\0\bv0_0\3\bv1_0\0\bv2_0\0\bv3_0\0\bv4_0\0\bv5_0\0\bv6_0\0\kvr0_0\1\kvr1_0\0\kvr2_0\0\kvr3_0\0\kvr4_0\0\kvr5_0\0\kvr6_0\0\tk0_0\736\tk1_0\20\tk2_0\311\tk3_0\0\tk4_0\320\tk5_0\84\tk6_0\29\kk0_0\8\kk1_0\0\kk2_0\0\kk3_0\0\kk4_0\1\kk5_0\0\kk6_0\0\dk0_0\10\dk1_0\1\dk2_0\2\dk3_0\0\dk4_0\2\dk5_0\1\dk6_0\1\tw0_0\11\tw1_0\0\tw2_0\49\tw3_0\28\tw4_0\10\tw5_0\5\tw6_0\54\tw7_0\382\tw8_0\47\te0_0\2\te1_0\0\te3_0\48\te2_0\0\te4_0\0\te5_0\0\te6_0\0\te7_0\0\te8_0\0\kw0_0\0\kw1_0\0\kw2_0\0\kw3_0\0\kw4_0\0\kw5_0\1\kw6_0\0\kw7_0\1\kw8_0\0\ke0_0\1\ke1_0\0\ke3_0\0\ke2_0\0\ke4_0\0\ke5_0\0\bw0_0\1\bw1_0\0\bw2_0\2\bw3_0\1\bw4_0\0\bw5_0\0\bw6_0\3\bw7_0\5\bw8_0\1\be0_0\0\be1_0\0\be3_0\1\be2_0\0\be4_0\0\be5_0\0\be8_0\0\be9_0\0\de6_0\0\de7_0\0\de8_0\0\sw0_0\0\sw1_0\0\sw2_0\26\sw3_0\0\sw4_0\0\sw5_0\15\sw6_0\4\sw7_0\53\sw8_0\0\se0_0\2\se1_0\0\se2_0\0\se3_0\6\se4_0\0\se5_0\0\hw0_0\0\hw1_0\0\hw2_0\3\hw3_0\0\hw4_0\0\hw5_0\5\hw6_0\1\hw7_0\8\hw8_0\0\he0_0\1\he1_0\0\he2_0\0\he3_0\3\he4_0\0\he5_0\0\EOF\1 \ No newline at end of file diff --git a/test/test-endpoints.sh b/test/test-endpoints.sh new file mode 100755 index 00000000..f91c1ffd --- /dev/null +++ b/test/test-endpoints.sh @@ -0,0 +1,77 @@ +#!/bin/sh +set -eu + +echo +echo "[test-endpoints]" +ENDPOINTS=" +asp.example.com/ 200 +asp.example.com/.htaccess 401 +asp.example.com/ASP/ 200 +asp.example.com/ASP/frontend/template.php 401 +asp.example.com/ASP/frontend/css/reset.css 200 +asp.example.com/ASP/frontend/js/jquery-ui.js 200 +asp.example.com/ASP/frontend/images/bf2logo.png 200 +asp.example.com/ASP/frontend/css/fonts/ptsans/PTS55F-webfont.woff 200 +asp.example.com/ASP/system 401 +asp.example.com/ASP/bf2statistics.php 200 +asp.example.com/ASP/getawardsinfo.aspx 200 +asp.example.com/ASP/getbackendinfo.aspx 200 +asp.example.com/ASP/getclaninfo.aspx 200 +asp.example.com/ASP/getleaderboard.aspx 200 +asp.example.com/ASP/getmapinfo.aspx 200 +asp.example.com/ASP/getplayerid.aspx 200 +asp.example.com/ASP/getplayerinfo.aspx 200 +asp.example.com/ASP/getrankinfo.aspx 200 +asp.example.com/ASP/getunlocksinfo.aspx 200 +asp.example.com/ASP/index.php 200 +asp.example.com/ASP/ranknotification.aspx 200 +asp.example.com/ASP/searchforplayers.aspx 200 +asp.example.com/ASP/selectunlock.aspx 200 + +bf2web.gamespy.com/ 200 +bf2web.gamespy.com/.htaccess 401 +bf2web.gamespy.com/ASP/ 200 +bf2web.gamespy.com/ASP/frontend/template.php 401 +bf2web.gamespy.com/ASP/frontend/css/reset.css 200 +bf2web.gamespy.com/ASP/frontend/js/jquery-ui.js 200 +bf2web.gamespy.com/ASP/frontend/images/bf2logo.png 200 +bf2web.gamespy.com/ASP/frontend/css/fonts/ptsans/PTS55F-webfont.woff 200 +bf2web.gamespy.com/ASP/system 401 +bf2web.gamespy.com/ASP/bf2statistics.php 200 +bf2web.gamespy.com/ASP/getawardsinfo.aspx 200 +bf2web.gamespy.com/ASP/getbackendinfo.aspx 200 +bf2web.gamespy.com/ASP/getclaninfo.aspx 200 +bf2web.gamespy.com/ASP/getleaderboard.aspx 200 +bf2web.gamespy.com/ASP/getmapinfo.aspx 200 +bf2web.gamespy.com/ASP/getplayerid.aspx 200 +bf2web.gamespy.com/ASP/getplayerinfo.aspx 200 +bf2web.gamespy.com/ASP/getrankinfo.aspx 200 +bf2web.gamespy.com/ASP/getunlocksinfo.aspx 200 +bf2web.gamespy.com/ASP/index.php 200 +bf2web.gamespy.com/ASP/ranknotification.aspx 200 +bf2web.gamespy.com/ASP/searchforplayers.aspx 200 +bf2web.gamespy.com/ASP/selectunlock.aspx 200 + +bf2sclone.example.com/ 200 +bf2sclone.example.com/.htaccess 401 +bf2sclone.example.com/cache 401 +bf2sclone.example.com/css/default.css 200 +bf2sclone.example.com/game-images/armies/0.png 200 +bf2sclone.example.com/js/nt2.js 200 +bf2sclone.example.com/queries/armies.list 401 +bf2sclone.example.com/queries/getArmiesByPID.php 401 +bf2sclone.example.com/site-images/online.png 200 +bf2sclone.example.com/template/config.inc.php.template 401 +bf2sclone.example.com/awards.inc.php 401 +bf2sclone.example.com/install.php.disabled 401 +" +command -v curl || apk add --no-cache curl +echo "$ENDPOINTS" | awk NF | while read -r i j; do + d=$( echo "$i" | cut -d '/' -f1 ) + if curl --head -skL http://$i --resolve $d:80:127.0.0.1 --resolve $d:443:127.0.0.1 2>&1 | grep -E "^HTTP/(1.1|2) $j " > /dev/null; then + echo "PASS: $i" + else + echo "FAIL: $i" + exit 1 + fi +done diff --git a/test/test-external-dns.sh b/test/test-external-dns.sh new file mode 100755 index 00000000..55c946d4 --- /dev/null +++ b/test/test-external-dns.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -eu + +echo +echo "[test-external-dns]" +DNS=" +192.168.1.100 battlefield2.available.gamespy.com +192.168.1.100 battlefield2.master.gamespy.com +192.168.1.100 battlefield2.ms14.gamespy.com +192.168.1.100 master.gamespy.com +192.168.1.100 motd.gamespy.com +192.168.1.100 gpsp.gamespy.com +192.168.1.100 gpcm.gamespy.com +192.168.1.100 gamespy.com +192.168.1.100 bf2web.gamespy.com +192.168.1.100 gamestats.gamespy.com +192.168.1.100 eapusher.dice.se +" +echo "$DNS" | awk NF | while read -r ip h; do + if nslookup $h coredns | grep -E "^Address: $ip" > /dev/null; then + echo "PASS: $h" + else + echo "FAIL: $h" + exit 1 + fi +done diff --git a/test/test-internal-dns.sh b/test/test-internal-dns.sh new file mode 100755 index 00000000..76916d13 --- /dev/null +++ b/test/test-internal-dns.sh @@ -0,0 +1,24 @@ +#!/bin/sh +set -eu + +echo +echo "[test-internal-dns]" +DNS=" +battlefield2.available.gamespy.com +battlefield2.master.gamespy.com +battlefield2.ms14.gamespy.com +master.gamespy.com +motd.gamespy.com +gpsp.gamespy.com +gpcm.gamespy.com +gamespy.com +bf2web.gamespy.com +" +echo "$DNS" | awk NF | grep -v '127.0.0' | while read -r h; do + if nslookup $h | grep -v '127.0.0' | grep -E '^Address: [0-9\.]+$'; then + echo "PASS: $h" + else + echo "FAIL: $h" + exit 1 + fi +done diff --git a/test/test-ready.sh b/test/test-ready.sh new file mode 100755 index 00000000..8b81f78f --- /dev/null +++ b/test/test-ready.sh @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu + +echo +echo "[test-ready] Waiting for stack to be ready" +s=0 +while true; do + nc -vz -w 1 asp 80 \ + && nc -vz -w 1 asp 9000 \ + && nc -vz -w 1 bf2sclone 80 \ + && nc -vz -w 1 bf2sclone 9000 \ + && nc -vz -w 1 db 3306 \ + && break || true + s=$(( $s + 1 )) + if [ "$s" -eq 100 ]; then + exit 1 + fi + echo "Retrying in 3 seconds" + sleep 3 +done diff --git a/test/test-routes.sh b/test/test-routes.sh new file mode 100755 index 00000000..cfaf9452 --- /dev/null +++ b/test/test-routes.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -eu + +echo +echo "[test-routes]" +URLS=" +http://asp/ 200 +http://asp/.htaccess 401 +http://asp/ASP/ 200 +http://asp/ASP/frontend/template.php 401 +http://asp/ASP/frontend/css/reset.css 200 +http://asp/ASP/frontend/js/jquery-ui.js 200 +http://asp/ASP/frontend/images/bf2logo.png 200 +http://asp/ASP/frontend/css/fonts/ptsans/PTS55F-webfont.woff 200 +http://asp/ASP/system 401 +http://asp/ASP/bf2statistics.php 200 +http://asp/ASP/getawardsinfo.aspx 200 +http://asp/ASP/getbackendinfo.aspx 200 +http://asp/ASP/getclaninfo.aspx 200 +http://asp/ASP/getleaderboard.aspx 200 +http://asp/ASP/getmapinfo.aspx 200 +http://asp/ASP/getplayerid.aspx 200 +http://asp/ASP/getplayerinfo.aspx 200 +http://asp/ASP/getrankinfo.aspx 200 +http://asp/ASP/getunlocksinfo.aspx 200 +http://asp/ASP/index.php 200 +http://asp/ASP/ranknotification.aspx 200 +http://asp/ASP/searchforplayers.aspx 200 +http://asp/ASP/selectunlock.aspx 200 + +http://bf2sclone/ 200 +http://bf2sclone/.htaccess 401 +http://bf2sclone/cache 401 +http://bf2sclone/css/default.css 200 +http://bf2sclone/game-images/armies/0.png 200 +http://bf2sclone/js/nt2.js 200 +http://bf2sclone/queries/armies.list 401 +http://bf2sclone/queries/getArmiesByPID.php 401 +http://bf2sclone/site-images/online.png 200 +http://bf2sclone/template/config.inc.php.template 401 +http://bf2sclone/awards.inc.php 401 +http://bf2sclone/install.php.disabled 401 + +http://phpmyadmin/ 200 +" +echo "$URLS" | awk NF | while read -r i j; do + if wget -q -SO- "$i" 2>&1 | grep "HTTP/1.1 $j " > /dev/null; then + echo "PASS: $i" + else + echo "FAIL: $i" + exit 1 + fi +done diff --git a/test/test-snapshots.sh b/test/test-snapshots.sh new file mode 100755 index 00000000..95925a78 --- /dev/null +++ b/test/test-snapshots.sh @@ -0,0 +1,19 @@ +#!/bin/sh +set -eu + +SCRIPT_DIR=$( cd "$( dirname "$0" )" && pwd ) +cd "$SCRIPT_DIR" + +echo +echo "[test-snapshots]" +command -v curl || apk add --no-cache curl +for i in ./snapshots/*.txt; do + RES=$( set -x; curl -s -A GameSpyHTTP/1.0 -H 'Content-Type: application/json' --data "@$i" http://asp/ASP/bf2statistics.php ) + echo "$RES"; echo + if [ "$( echo "$RES" | head -c1 )" = 'O' ]; then + echo "PASS: $i" + else + echo "FAIL: $i" + exit 1 + fi +done diff --git a/test/test.sh b/test/test.sh new file mode 100755 index 00000000..7cb729c1 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,95 @@ +#!/bin/sh +set -eu + +TEST=${1:-} # Test environment +UP=${2:-} # Whether to docker compose up and down the test stack +CACHE=${3:-} # Whether to override with docker-compose.build.yml + +# Validation and normalization +if ! echo "$TEST" | grep -E '^(dev|prod1|prod2|dns)$' > /dev/null; then + echo "Specify TEST as the first argument. E.g. 'dev', 'prod1', 'prod2', 'dns'" + exit 1 +fi +if [ -n "$CACHE" ]; then + CACHE='-f docker-compose.build.yml' +fi + +SCRIPT_DIR=$( cd "$( dirname "$0" )" && pwd ) +ERR= +setup_test() { + cd "$SCRIPT_DIR" + docker compose up -d + if [ -n "$UP" ]; then + setup + fi + run +} +cleanup_test() { + ERR=$? + if [ -n "$UP" ]; then + cleanup + fi + docker compose stop + if [ -z "$ERR" ] || [ "$ERR" = 0 ]; then + echo "All tests succeeded" + else + echo "Some tests failed" + echo "Exit code: $ERR" + exit "$ERR" + fi +} +trap cleanup_test INT TERM EXIT + +echo "Testing..." +if [ "$TEST" = 'dev' ]; then + setup() { + (cd .. && docker compose -f docker-compose.yml $CACHE up --build -d) + } + run() { + docker exec $( docker compose ps -q test-container-networking ) ./test-ready.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-routes.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-snapshots.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-internal-dns.sh + } + cleanup() { + (cd .. && docker compose stop) + } +fi +if [ "$TEST" = 'prod1' ]; then + setup() { + (cd ../docs/bf2hub-bf2stats-example && docker compose -f docker-compose.yml $CACHE up --build -d) + } + run() { + docker exec $( docker compose ps -q test-container-networking ) ./test-ready.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-routes.sh + docker exec $( docker compose ps -q test-host-networking ) ./test-endpoints.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-snapshots.sh + } + cleanup() { + (cd ../docs/bf2hub-bf2stats-example && docker compose -f docker-compose.yml -f docker-compose.build.yml stop) + } +fi +if [ "$TEST" = 'prod2' ]; then + setup() { + (cd ../docs/full-bf2-stack-example && docker compose -f docker-compose.yml $CACHE up --build -d) + } + run() { + docker exec $( docker compose ps -q test-container-networking ) ./test-ready.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-routes.sh + docker exec $( docker compose ps -q test-host-networking ) ./test-endpoints.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-snapshots.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-internal-dns.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-external-dns.sh + } + cleanup() { + (cd ../docs/full-bf2-stack-example && docker compose -f docker-compose.yml $CACHE stop) + } +fi +if [ "$TEST" = 'dns' ]; then + run() { + docker exec $( docker compose ps -q test-container-networking ) ./test-ready.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-coredns.sh + docker exec $( docker compose ps -q test-container-networking ) ./test-internal-dns.sh + } +fi +setup_test