Merge branch 'release/v1.9.0' of hardi/opt-cc into master

pull/55/head
hardi 2019-02-11 19:05:55 +01:00 committed by Gogs
commit 75a20e54cb
55 changed files with 993 additions and 1827 deletions

5
.gitignore vendored
View File

@ -45,11 +45,11 @@ Thumbs.db
.directory
# Internal Data
public/
mongodb-data/
/public/
server/resource/
server/apib/dredd/data/tmp-resource
backup/
!backup.sh
# System
.npm/
@ -59,4 +59,3 @@ backup/
.cache/motd.legal-displayed
.profile
.ssh/

View File

@ -4,7 +4,7 @@
cd $(dirname $0)
# array of available collection names
col=(app_user awarding campaign decoration logBudget logFlag logKill logPoints logRespawn logRevive logTransport logVehicle player promotion rank squad user war )
col=(app_user awarding campaign decoration logBudget logFlag logKill logPlayerCount logPoints logRespawn logRevive logServerFps logTransport logVehicle player promotion rank squad user war)
if [ -z "$1" ]
then

View File

@ -1,9 +1,9 @@
<code_scheme name="OPT-CC" version="173">
<option name="FORMATTER_TAGS_ENABLED" value="true" />
<JSCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
</JSCodeStyleSettings>
<TypeScriptCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="USE_DOUBLE_QUOTES" value="false" />
<option name="USE_CHAINED_CALLS_GROUP_INDENTS" value="true" />
</TypeScriptCodeStyleSettings>
@ -11,6 +11,8 @@
<option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
<option name="ALIGN_MULTILINE_CHAINED_METHODS" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />

Binary file not shown.

View File

@ -1,6 +1,6 @@
{
"name": "opt-cc",
"version": "1.8.6",
"version": "1.9.0",
"author": "Florian Hartwich <hardi@noarch.de>",
"private": true,
"scripts": {

View File

@ -5,10 +5,13 @@ Update an army members signature image
**Permission: 4**
+ Parameters
+ userId: `5ab68d42f547ed304064e5f7` (string, required) - army members unique user id
+ Request (application/json)
{}
+ Attributes (object)
+ Response 200 (application/json; charset=utf-8)

View File

@ -1,8 +1,9 @@
### List Users [GET /users{?q,fractFilter,limit,offset}]
### List Users [GET /users{?q,fractFilter,squadId,decorationId,limit,offset}]
Get single army member information
+ Parameters
+ q: `hardi` (string, optional) - filter string which filters for partial username
+ fractFilter: `BLUFOR` (enum[string], optional) - Field to filter by fraction
@ -12,17 +13,15 @@ Get single army member information
+ `OPFOR`
+ `GLOBAL`
+ squadId: `591470249e9fae286e008e31` (string, optional) - Field to filter by membership of certain squad
+ squadId: `5aba54eaeadcce6332c6a774` (string, optional) - Field to filter by membership of certain squad
+ decorationId: `5abd3dff6e6a0334d95b8ba0` (string, optional) - Field to filter by ownership of certain decoration
+ limit: 20 (number, optional)
Maximum number of users to return
+ limit: 20 (number, optional) - Maximum number of users to return
+ Default: Infinity
+ offset: 0 (number, optional)
Offset into result-set (useful for pagination)
+ offset: 0 (number, optional) - Offset into result-set (useful for pagination)
+ Default: 0
@ -40,6 +39,7 @@ Get single army member information
Get single army member information
+ Parameters
+ id: `5ab68d42f547ed304064e5f7` (string, required) - unique id of army-member
+ Response 200 (application/json; charset=utf-8)

View File

@ -1,4 +1,5 @@
# Campaign (object)
Campaign entity
## Properties
@ -9,8 +10,10 @@ Campaign entity
+ __v: 0 (number, required) - version number
#WarCampaign (object)
Cmpaign entity with attached War collection
## Properties
+ _id: `5abd55ea9e30a76bfef747d6` (string, required) - unique id of the campaign
+ title: `Ein Kessel Buntes` (string, required) - display title of the campaign
+ wars (array[WarWithPlayers], requied)
+ wars: WarWithPlayers (array[WarWithPlayers], required)

View File

@ -14,6 +14,8 @@ Basic player statistic information object
+ respawn: 2 (number, required) - sum of respawns
+ flagTouch: 1 (number, required) - sum of flag captures
+ revive: 0 (number, required) - sum of revives
+ travelDistance: 16535 (number, optional) - sum of transport meters as passenger
+ driverDistance: 1250 (number, optional) - sum of transport meters as pilot/driver
# WarPlayer (BasicPlayer)
@ -22,15 +24,16 @@ A player campaign statistics object
## Properties
+ _id: `5ab68d42f547ed304064e5f7` (string, required) - unique id of the army member
+ warId: `5abf65ae3fc5fa349ffd5ca3` (string, required) - war in which this player took part
+ steamUUID: `76561192214911200` (string, required) - unique ID for STEAM platform account
+ sort: 1 (number, required) - sorting number calculated by (kill + revive + flagTouch - friendlyFire - death - respawn)
+ steamUUID: 76561192214911200 (number, optional) - unique ID for STEAM platform account
+ performance: `5abf65ae3fc5fa349ffd5cs2` (string, optional) - id of corresponding performance log entry
+ timestamp: `2018-02-24T01:01:25.825Z` - the entity creation timestamp
+ updatedAt: `2018-02-24T01:01:25.825Z` - the version timestamp
+ __v: 0 (number, required) - the version number of the object
# HighscorePlayer (BasicPlayer)
A player object as resturned for the highscore arrays
A player object as returned for the highscore arrays
## Properties
+ warId: War (War, required) - war in which this player took part
+ num: 1

View File

@ -23,4 +23,4 @@ A war as used in statistics
A war response object on creation
## Properties
+ players (array[WarPlayer], required) - collection of all participating players with their statistics
+ players (array[WarPlayer], required, fixed-type) - collection of all participating players with their statistics

View File

@ -16,56 +16,66 @@ FORMAT: 1A
# Group Access
## Endpoints [/auth]
:[Gists](auth/signup.apib)
:[Gists](auth/login.apib)
# Group Admin
## Account [/account]
:[Gists](admin/account.apib)
## Commands [/cmd]
:[Gists](admin/signature.apib)
# Group Army Overview
# Group Army Management
## Army [/overview]
:[Gists](army-management/army.apib)
# Group Awardings
## Awardings [/awarding]
:[Gists](army-management/awardings.apib)
# Group Campaigns
:[Gists](statistics/campaigns.apib)
# Group Decorations
## Decorations [/decorations]
:[Gists](army-management/decorations.apib)
# Group Logs
:[Gists](statistics/logs.apib)
# Group Players
:[Gists](statistics/players.apib)
# Group Promotion
## Promotion [/promotions]
:[Gists](army-management/promotions.apib)
# Group Ranks
## Ranks [/ranks]
:[Gists](army-management/ranks.apib)
# Group Squads
## Squads [/squads]
:[Gists](army-management/squads.apib)
# Group Users
## Users [/user]
:[Gists](army-management/users.apib)
# Group Wars
# Group Statistics
## Campaigns [/campaigns]
:[Gists](statistics/campaigns.apib)
## Logs [/logs]
:[Gists](statistics/logs.apib)
## Players [/players]
:[Gists](statistics/players.apib)
## Wars [/wars]
:[Gists](statistics/wars.apib)

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca4"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicle":0,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca5"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca6"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca7"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca8"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca9"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5caa"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicle":0,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cab"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicle":1,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbc"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicle":0,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbd"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbe"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc1"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc0"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc2"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicle":0,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc3"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicle":1,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbf"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicle":0,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca4"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca5"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca6"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca7"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca8"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5ca9"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5caa"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65ae3fc5fa349ffd5cab"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65ae3fc5fa349ffd5ca3"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicleLight":1,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:40:46.712Z"},"updatedAt":{"$date":"2018-03-31T10:40:46.712Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbc"},"name":"Pumarang","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119805032149e+16,"respawn":1,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":1,"revive":0,"flagTouch":0,"sort":-2,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbd"},"name":"Mercurat","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982788425e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbe"},"name":"KalleK","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797767603e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc1"},"name":"Philipp","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119804179206e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc0"},"name":"LyrikEmu","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611982189104e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc2"},"name":"Wiesl","fraction":"BLUFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.65611980596481e+16,"respawn":0,"kill":1,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":1,"death":0,"revive":1,"flagTouch":1,"sort":2,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cc3"},"name":"Murda]X[","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119797112163e+16,"respawn":0,"kill":0,"vehicleLight":1,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.460Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.460Z"},"__v":0}
{"_id":{"$oid":"5abf65d83fc5fa349ffd5cbf"},"name":"MAPster","fraction":"OPFOR","warId":{"$oid":"5abf65d83fc5fa349ffd5cbb"},"steamUUID":7.656119800988213e+16,"respawn":0,"kill":0,"vehicleLight":0,"vehicleHeavy":0,"vehicleAir":0,"steamUUID":76561192214911200,"friendlyFire":0,"death":0,"revive":0,"flagTouch":0,"sort":0,"timestamp":{"$date":"2018-03-31T10:41:28.459Z"},"updatedAt":{"$date":"2018-03-31T10:41:28.459Z"},"__v":0}

View File

@ -33,4 +33,4 @@ Get statistics for a single player for all wars of a campaign he took part at
+ Attributes
+ name: `Pumarang` (string, required) - latest used playername
+ campaign (Campaign,required) - campaign reflected from request is
+ players (array[WarPlayer],required) - collection of player instances in the campaign
+ players (array[HighscorePlayer],required, fixed-type) - collection of player instances in the campaign

View File

@ -32,6 +32,7 @@ const LogBudgetSchema = new Schema({
},
}, {
collection: 'logBudget',
versionKey: false,
});
// optional more indices
LogBudgetSchema.index({war: 1});

View File

@ -28,6 +28,7 @@ const LogFlagSchema = new Schema({
},
}, {
collection: 'logFlag',
versionKey: false,
});
// optional more indices
LogFlagSchema.index({war: 1, player: 1});

View File

@ -40,6 +40,7 @@ const LogKillSchema = new Schema({
},
}, {
collection: 'logKill',
versionKey: false,
});
// optional more indices
LogKillSchema.index({war: 1, shooter: 1, target: 1});

View File

@ -0,0 +1,35 @@
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LogPlayerCountSchema = new Schema({
war: {
type: mongoose.Schema.Types.ObjectId,
ref: 'War',
required: true,
},
time: {
type: Date,
required: true,
},
countBlufor: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
},
countOpfor: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
},
}, {
collection: 'logPlayerCount',
versionKey: false,
});
// optional more indices
LogPlayerCountSchema.index({war: 1});
module.exports = mongoose.model('LogPlayerCount', LogPlayerCountSchema);

View File

@ -32,6 +32,7 @@ const LogKillSchema = new Schema({
},
}, {
collection: 'logPoints',
versionKey: false,
});
// optional more indices
LogKillSchema.index({war: 1, shooter: 1, target: 1});

View File

@ -19,6 +19,7 @@ const LogRespawnSchema = new Schema({
},
}, {
collection: 'logRespawn',
versionKey: false,
});
// optional more indices
LogRespawnSchema.index({war: 1, player: 1});

View File

@ -32,6 +32,7 @@ const LogReviveSchema = new Schema({
},
}, {
collection: 'logRevive',
versionKey: false,
});
// optional more indices
LogReviveSchema.index({war: 1, medic: 1});

View File

@ -0,0 +1,47 @@
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LogServerFpsSchema = new Schema({
war: {
type: mongoose.Schema.Types.ObjectId,
ref: 'War',
required: true,
},
entityName: {
type: String,
required: true,
},
singleAvgFps: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
},
singleMinFps: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
},
avgFps: [{
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
}],
minFps: [{
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: true,
}],
}, {
collection: 'logServerFps',
versionKey: false,
});
// optional more indices
LogServerFpsSchema.index({war: 1});
module.exports = mongoose.model('LogServerFps', LogServerFpsSchema);

View File

@ -34,6 +34,7 @@ const LogTransportSchema = new Schema({
},
}, {
collection: 'logTransport',
versionKey: false,
});
// optional more indices
LogTransportSchema.index({war: 1, driver: 1});

View File

@ -41,6 +41,7 @@ const LogVehicleKillSchema = new Schema({
},
}, {
collection: 'logVehicle',
versionKey: false,
});
// optional more indices
LogVehicleKillSchema.index({war: 1, shooter: 1, target: 1});

View File

@ -72,17 +72,30 @@ const PlayerSchema = new Schema({
set: (v) => Math.round(v),
required: true,
},
sort: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
},
steamUUID: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
},
}, {
performance: {
type: mongoose.Schema.Types.ObjectId,
ref: 'LogServerFps',
required: false,
},
travelDistance: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: false,
},
driverDistance: {
type: Number,
get: (v) => Math.round(v),
set: (v) => Math.round(v),
required: false,
},
},
{
collection: 'player',
timestamps: {createdAt: 'timestamp'},
});

View File

@ -12,9 +12,22 @@ const checkMT = require('../middleware/permission-check').checkMT;
const routerHandling = require('../middleware/router-handling');
const idValidator = require('../middleware/validators').idValidator;
const fs = require('fs');
const resourceLocation = require('../middleware/resource-location').resourceLocation().concat('/logs/');
// Mongoose Model using mongoDB
const CampaignModel = require('../models/campaign');
const WarModel = require('../models/war');
const PlayerModel = require('../models/player');
const LogKillModel = require('../models/logs/kill');
const LogVehicleKillModel = require('../models/logs/vehicle');
const LogRespawnModel = require('../models/logs/respawn');
const LogReviveModel = require('../models/logs/revive');
const LogTransportModel = require('../models/logs/transport');
const LogFlagModel = require('../models/logs/flag');
const LogBudgetModel = require('../models/logs/budget');
const LogPointsModel = require('../models/logs/points');
const LogPlayerCountModel = require('../models/logs/player-count');
// util
const genericGetById = require('./_generic').genericGetById;
@ -88,20 +101,49 @@ campaigns.route('/:id')
})
.delete((req, res, next) => {
CampaignModel.findByIdAndRemove(req.params.id, (err, item) => {
if (err) {
err.status = codes.wrongrequest;
return next(err);
} else if (!item) {
err = new Error('item not found');
err.status = codes.notfound;
return next(err);
}
WarModel.find({campaign: req.params.id}).remove().exec();
// TODO: remove all the war logs from fs here!!!
// TODO: remove all LOG entries from DB!!!
res.locals.processed = true;
next();
WarModel.find({campaign: req.params.id}, (err, wars) => {
wars.forEach((item) => {
// delete linked appearances
PlayerModel.find({warId: item._id}).remove().exec();
LogKillModel.find({war: item._id}).remove().exec();
LogVehicleKillModel.find({war: item._id}).remove().exec();
LogRespawnModel.find({war: item._id}).remove().exec();
LogReviveModel.find({war: item._id}).remove().exec();
LogFlagModel.find({war: item._id}).remove().exec();
LogBudgetModel.find({war: item._id}).remove().exec();
LogTransportModel.find({war: item._id}).remove().exec();
LogPointsModel.find({war: item._id}).remove().exec();
LogPlayerCountModel.find({war: item._id}).remove().exec();
// check if logfiles exist and delete from fs
const warDir = resourceLocation + item.id;
if (fs.existsSync(warDir)) {
const cleanLog = warDir + '/clean.log';
if (fs.existsSync(cleanLog)) {
fs.unlink(cleanLog, (err) => {
});
}
const sourceLog = warDir + '/war.log';
if (fs.existsSync(sourceLog)) {
fs.unlink(sourceLog, (err) => {
});
}
fs.rmdir(warDir, (err) => {
});
}
});
CampaignModel.findByIdAndRemove(req.params.id, (err, item) => {
if (err) {
err.status = codes.wrongrequest;
return next(err);
} else if (!item) {
err = new Error('item not found');
err.status = codes.notfound;
return next(err);
}
res.locals.processed = true;
next();
});
});
})

View File

@ -4,6 +4,9 @@
const express = require('express');
const async = require('async');
// HTTP status codes by name
const codes = require('./http-codes');
const routerHandling = require('../middleware/router-handling');
// Mongoose Model using mongoDB
@ -15,6 +18,8 @@ const LogVehicleModel = require('../models/logs/vehicle');
const LogTransportModel = require('../models/logs/transport');
const LogFlagModel = require('../models/logs/flag');
const LogPointsModel = require('../models/logs/points');
const LogPlayerCountModel = require('../models/logs/player-count');
const LogServerFpsModel = require('../models/logs/server-fps');
const logsRouter = new express.Router();
@ -23,7 +28,7 @@ const processLogRequest = (model, filter, res, next) => {
if (err) return next(err);
if (!log || log.length === 0) {
const err = new Error('No logs found');
err.status = require('./http-codes').notfound;
err.status = codes.notfound;
return next(err);
}
res.locals.items = log;
@ -45,6 +50,7 @@ logsRouter.route('/:warId')
const vehicleObjects = LogVehicleModel.find(filter, {}, sort);
const transportObjects = LogTransportModel.find(filter, {}, sort);
const flagObjects = LogFlagModel.find(filter, {}, sort);
const playerCountObjects = LogPlayerCountModel.find(filter, {}, sort);
const resources = {
points: pointsObjects.exec.bind(pointsObjects),
budget: budgetObjects.exec.bind(budgetObjects),
@ -54,6 +60,7 @@ logsRouter.route('/:warId')
vehicle: killObjects.exec.bind(vehicleObjects),
transport: transportObjects.exec.bind(transportObjects),
flag: flagObjects.exec.bind(flagObjects),
playerCount: playerCountObjects.exec.bind(playerCountObjects),
};
async.parallel(resources, (error, results) => {
@ -151,6 +158,24 @@ logsRouter.route('/:warId/points')
routerHandling.httpMethodNotAllowed
);
logsRouter.route('/:warId/performance')
.get((req, res, next) => {
const filter = {war: req.params.warId};
LogServerFpsModel.find(filter, (err, items) => {
if (err) return next(err);
if (!items) {
const err = new Error('No logs found');
err.status = codes.notfound;
return next(err);
}
res.locals.items = items;
next();
});
})
.all(
routerHandling.httpMethodNotAllowed
);
logsRouter.use(routerHandling.emptyResponse);
module.exports = logsRouter;

View File

@ -33,6 +33,8 @@ const LogTransportModel = require('../models/logs/transport');
const LogFlagModel = require('../models/logs/flag');
const LogBudgetModel = require('../models/logs/budget');
const LogPointsModel = require('../models/logs/points');
const LogPlayerCountModel = require('../models/logs/player-count');
const LogServerFpsModel = require('../models/logs/server-fps');
// util
const genericPatch = require('./_generic').genericPatch;
@ -58,53 +60,79 @@ wars.route('/')
})
.post(apiAuthenticationMiddleware, checkMT, upload.single('log'), (req, res, next) => {
const body = req.body;
const warBody = new WarModel(body);
const body = req.body;
const warBody = new WarModel(body);
if (req.file) {
fs.readFile(req.file.buffer, (file, err) => {
if (err) {
return next(err);
}
const lineArray = file.toString().split('\n');
const statsResult = parseWarLog(lineArray, warBody);
statsResult.war.save((err, war) => {
if (req.file) {
fs.readFile(req.file.buffer, (file, err) => {
if (err) {
return next(err);
}
PlayerModel.create(statsResult.players, (err) => {
const lineArray = file.toString().split('\n');
const statsResult = parseWarLog(lineArray, warBody);
statsResult.war.save((err, war) => {
if (err) {
return next(err);
}
LogKillModel.create(statsResult.kills, () => {
LogVehicleKillModel.create(statsResult.vehicles, () => {
LogRespawnModel.create(statsResult.respawn, () => {
LogReviveModel.create(statsResult.revive, () => {
LogFlagModel.create(statsResult.flag, () => {
LogBudgetModel.create(statsResult.budget, () => {
LogTransportModel.create(statsResult.transport, () => {
LogPointsModel.create(statsResult.points, () => {
const folderName = resourceLocation.concat(war._id);
mkdirp(folderName, (err) => {
if (err) return next(err);
LogKillModel.create(statsResult.kills, (err) => {
if (err) console.log(err);
LogVehicleKillModel.create(statsResult.vehicles, (err) => {
if (err) console.log(err);
LogRespawnModel.create(statsResult.respawn, (err) => {
if (err) console.log(err);
LogReviveModel.create(statsResult.revive, (err) => {
if (err) console.log(err);
LogFlagModel.create(statsResult.flag, (err) => {
if (err) console.log(err);
LogBudgetModel.create(statsResult.budget, (err) => {
if (err) console.log(err);
LogTransportModel.create(statsResult.transport, (err) => {
if (err) console.log(err);
LogPlayerCountModel.create(statsResult.playerCount, (err) => {
if (err) console.log(err);
LogPointsModel.create(statsResult.points, (err) => {
if (err) console.log(err);
LogServerFpsModel.create(statsResult.serverFps, (err, serverPerformanceEntries) => {
if (err) console.log(err);
if (serverPerformanceEntries) {
serverPerformanceEntries.forEach((entry) => {
const idx = statsResult.players
.findIndex((player) => player.name === entry.entityName);
if (idx !== -1) {
const player = statsResult.players[idx];
player['performance'] = entry._id;
statsResult.players[idx] = player;
}
});
}
PlayerModel.create(statsResult.players, (err) => {
if (err) {
return next(err);
}
const folderName = resourceLocation.concat(war._id);
mkdirp(folderName, (err) => {
if (err) return next(err);
// save clean log file
const cleanFile = fs.createWriteStream(folderName + '/clean.log');
statsResult.clean.forEach((cleanLine) => {
cleanFile.write(cleanLine + '\n\n');
// save clean log file
const cleanFile = fs.createWriteStream(folderName + '/clean.log');
statsResult.clean.forEach((cleanLine) => {
cleanFile.write(cleanLine + '\n\n');
});
cleanFile.end();
// save raw log file
const rawFile = fs.createWriteStream(folderName + '/war.log');
lineArray.forEach((rawLine) => {
rawFile.write(rawLine + '\n');
});
rawFile.end();
res.status(codes.created);
res.locals.items = war;
next();
});
});
});
cleanFile.end();
// save raw log file
const rawFile = fs.createWriteStream(folderName + '/war.log');
lineArray.forEach((rawLine) => {
rawFile.write(rawLine + '\n');
});
rawFile.end();
res.status(codes.created);
res.locals.items = war;
next();
});
});
});
@ -116,13 +144,13 @@ wars.route('/')
});
});
});
});
} else {
const err = new Error('no Logfile provided');
err.status = codes.wrongmediasend;
next(err);
} else {
const err = new Error('no Logfile provided');
err.status = codes.wrongmediasend;
next(err);
}
}
})
)
.all(
routerHandling.httpMethodNotAllowed
@ -177,6 +205,7 @@ wars.route('/:id')
LogBudgetModel.find({war: item._id}).remove().exec();
LogTransportModel.find({war: item._id}).remove().exec();
LogPointsModel.find({war: item._id}).remove().exec();
LogPlayerCountModel.find({war: item._id}).remove().exec();
// check if logfiles exist and delete from fs
const warDir = resourceLocation + req.params.id;

View File

@ -23,6 +23,20 @@ const vehicleRegex = /(vehicle:\s(.*?)\))/;
const categoryRegex = /(category:\s(.*?)\))/;
const bluforPlayerCountRegex = /NATO\s(\d*)/;
const opforPlayerCountRegex = /CSAT\s(\d*)/;
const timestampRegex = /LOG:\s(\d*:\d*:\d*)\s---/;
const singleMinFpsRegex = /Single min\. FPS for (.*):\s(\d*.\d*)"/; // group1 = entity name, group2 = value
const singleAvgFpsRegex = /Single avg\. FPS for (.*):\s(\d*.\d*)"/; // group1 = entity name, group2 = value
const minFpsRegex = /Min\. FPS for (.*):\s\[(.*)\]"/; // group1 = entity name, group2 = comma separated values
const avgFpsRegex = /Avg\. FPS for (.*):\s\[(.*)\]"/; // group1 = entity name, group2 = comma separated values
const parseWarLog = (lineArray, war) => {
let flagBlufor = true;
let flagOpfor = true;
@ -41,6 +55,8 @@ const parseWarLog = (lineArray, war) => {
flag: [],
transport: [],
players: [],
playerCount: [],
serverFps: [],
};
const VEHICLE_BLACKLIST = [
@ -111,6 +127,7 @@ const parseWarLog = (lineArray, war) => {
const kill = {
war: war._id,
time: getFullTimeDate(war.date, line.split(WHITESPACE)[5]),
friendlyFire: false,
};
if (shooter) {
kill.shooter = shooter.name;
@ -245,6 +262,56 @@ const parseWarLog = (lineArray, war) => {
fraction: driver ? driver.fraction : 'NONE',
distance: distance,
});
} else if (line.includes('(Spieleranzahl)')) {
stats.clean.push(line);
const timestamp = (timestampRegex.exec(line))[1];
const countBlufor = (bluforPlayerCountRegex.exec(line))[1];
const countOpfor = (opforPlayerCountRegex.exec(line))[1];
stats.playerCount.push({
war: war.id,
time: getFullTimeDate(war.date, timestamp),
countBlufor: countBlufor,
countOpfor: countOpfor,
});
} else if (line.includes('(FPS)')) {
stats.clean.push(line);
const updateServerFpsLogEntry = (entityName, addKey, addValue) => {
const idx = stats.serverFps.findIndex((entry) => entry.entityName === entityName);
if (idx === -1) {
stats.serverFps.push({
war: war.id,
entityName: entityName,
[addKey]: addValue,
});
return;
}
const entity = stats.serverFps[idx];
entity[addKey] = addValue;
stats.serverFps[idx] = entity;
};
const singleMinMatch = singleMinFpsRegex.exec(line);
if (singleMinMatch) {
updateServerFpsLogEntry(singleMinMatch[1], 'singleMinFps', singleMinMatch[2]);
} else {
const singleAvgMatch = singleAvgFpsRegex.exec(line);
if (singleAvgMatch) {
updateServerFpsLogEntry(singleAvgMatch[1], 'singleAvgFps', singleAvgMatch[2]);
} else {
const minCollectionMatch = minFpsRegex.exec(line);
if (minCollectionMatch) {
updateServerFpsLogEntry(minCollectionMatch[1], 'minFps', minCollectionMatch[2].split(','));
} else {
const avgCollectionMatch = avgFpsRegex.exec(line);
if (avgCollectionMatch) {
updateServerFpsLogEntry(avgCollectionMatch[1], 'avgFps', avgCollectionMatch[2].split(','));
}
}
}
}
} else if (line.includes('(Fraktionsuebersicht)') || line.includes('Fraktionsübersicht')) {
/**
* PLAYERS
@ -287,9 +354,31 @@ const parseWarLog = (lineArray, war) => {
stats.players[i]['flagTouch'] = stats.flag.filter((flag) => flag.player === playerName).length;
stats.players[i]['sort'] = stats.players[i]['kill'] + stats.players[i]['revive'] +
stats.players[i]['flagTouch']
- stats.players[i]['friendlyFire'] - stats.players[i]['death'] - stats.players[i]['respawn'];
let playerTravelDistance = stats.transport.filter((transport) => transport.passenger === playerName)
.map((transport) => transport.distance)
.reduce((total, num) => total + Math.round(num), 0);
if (playerTravelDistance > 0) {
stats.players[i]['travelDistance'] = playerTravelDistance;
}
let driverDistance = 0;
const driverTransports = stats.transport.filter((transport) => transport.driver === playerName);
for (let i = 0; i < driverTransports.length; i++) {
const curr = driverTransports[i];
if (i < driverTransports.length - 1) {
const next = driverTransports[i + 1];
if ((next.time.getTime() - curr.time.getTime()) < 2 * 60000) { // only track once in 2 min range
continue;
}
driverDistance += curr.distance;
} else {
driverDistance += curr.distance;
}
}
if (driverDistance > 0) {
stats.players[i]['driverDistance'] = driverDistance;
}
}
stats.war.playersBlufor = stats.players.filter((player) => player.fraction === 'BLUFOR').length;

View File

@ -11,6 +11,7 @@ import {SpinnerService} from './services/user-interface/spinner/spinner.service'
import {TranslateService} from '@ngx-translate/core';
import {SettingsService} from './services/settings.service';
import {environment} from '../environments/environment';
import {SnackBarService} from './services/user-interface/snack-bar/snack-bar.service';
declare function require(url: string);
@ -52,6 +53,7 @@ export class AppComponent implements OnInit {
'stats-fraction': 'stats/fraction-btn',
'stats-player': 'stats/player-stats-btn',
'stats-scoreboard': 'stats/scoreboard-btn',
'stats-performance': 'stats/performance-stats-btn',
// --SCOREBOARD--
'death': 'stats/scoreboard/death',
'flagTouch': 'stats/scoreboard/flag-touch',
@ -63,6 +65,8 @@ export class AppComponent implements OnInit {
'vehicleAir': 'stats/scoreboard/vehicle-air',
'vehicleHeavy': 'stats/scoreboard/vehicle-heavy',
'vehicleLight': 'stats/scoreboard/vehicle-light',
'travelDistance': 'stats/scoreboard/travel-distance',
'driverDistance': 'stats/scoreboard/driver-distance',
// --------LOCALE---------
'flag-de': 'locale/de',
'flag-en': 'locale/en',
@ -83,6 +87,7 @@ export class AppComponent implements OnInit {
private spinnerService: SpinnerService,
private translate: TranslateService,
private settingsService: SettingsService,
private snackBarService: SnackBarService,
@Inject(DOCUMENT) private document) {
this.initMaterialSvgIcons();
@ -91,6 +96,7 @@ export class AppComponent implements OnInit {
router.events.subscribe(event => {
if (event instanceof NavigationStart) {
this.spinnerService.activate();
this.snackBarService.dismiss();
}
if (event instanceof NavigationEnd) {
this.spinnerService.deactivate();

View File

@ -35,6 +35,9 @@ export interface Player {
revive?: number;
respawn?: number;
flagTouch?: number;
performance?: string;
travelDistance?: number;
driverDistance?: number;
}
export interface CampaignPlayer {

View File

@ -68,4 +68,8 @@ export class LogsService {
params.append('defend', defendOnly ? 'true' : '');
return this.httpGateway.get(this.config.apiLogsPath + '/' + warId + '/flag', params);
}
getPerformanceLogs(warId: string) {
return this.httpGateway.get(this.config.apiLogsPath + '/' + warId + '/performance');
}
}

View File

@ -29,6 +29,10 @@ export class SnackBarService {
return this.snackbar.open(message, action, config);
}
dismiss() {
this.snackbar.dismiss();
}
showSuccess(i18n: string) {
this.translate.get(i18n).subscribe((translated) => {
return this.show(translated, undefined, 2500, ['custom-snack-bar', 'label-success']);

View File

@ -53,7 +53,7 @@ export class CampaignPlayerDetailComponent implements OnInit {
respawnDeathRatio = 0;
maxRespawnDeathRatio = 1;
playerAttributeNameMap = PlayerUtils.attributeDisplayNames.slice(2, PlayerUtils.attributeDisplayNames.length);
playerAttributeNameMap = PlayerUtils.tmpAttributeDisplayNames.slice(2, PlayerUtils.tmpAttributeDisplayNames.length);
constructor(private playerService: PlayerService,
private translate: TranslateService) {

View File

@ -24,7 +24,7 @@ export class StatisticHighScoreComponent implements OnInit {
playersStored = {};
playerAttributeDisplayNames = PlayerUtils.attributeDisplayNames.slice(2, PlayerUtils.attributeDisplayNames.length);
playerAttributeDisplayNames = PlayerUtils.tmpAttributeDisplayNames.slice(2, PlayerUtils.tmpAttributeDisplayNames.length);
readonly fraction = Fraction;

View File

@ -13,6 +13,7 @@ import {WarHeaderComponent} from './war/war-header/war-header.component';
import {LoginGuardMT} from '../login';
import {CampaignNavigationComponent} from './campaign/campaign-navigation/campaign-navigation.component';
import {StatisticOverviewComponent} from './campaign/overview/campaign-overview.component';
import {ServerStatsComponent} from './war/server-stats/server-stats.component';
export const statsRoutes: Routes = [
@ -69,5 +70,6 @@ export const statsRouterModule: ModuleWithProviders = RouterModule.forChild(stat
export const statsRoutingComponents = [StatisticComponent, StatisticOverviewComponent, StatisticHighScoreComponent,
CampaignSubmitComponent, WarListComponent, WarSubmitComponent, WarHeaderComponent, ScoreboardComponent,
FractionStatsComponent, CampaignPlayerDetailComponent, WarItemComponent, CampaignNavigationComponent];
FractionStatsComponent, CampaignPlayerDetailComponent, WarItemComponent, CampaignNavigationComponent,
ServerStatsComponent];

View File

@ -4,8 +4,8 @@
#group="matButtonToggleGroup"
[(ngModel)]="activeChartSelect"
(change)="selectChart(group.value)">
<mat-button-toggle *ngFor="let label of labelsAsString" value="{{label}}">
{{label | translate}}
<mat-button-toggle *ngFor="let labelKey of labelsKeys" value="{{labels[labelKey]}}">
{{labels[labelKey] | translate}}
</mat-button-toggle>
</mat-button-toggle-group>

View File

@ -39,24 +39,15 @@ export class FractionStatsComponent implements OnInit, OnChanges {
tmpReviveData;
tmpStabilizeData;
tmpFlagCaptureData;
tmpPlayerCountData;
colorScheme = {
domain: [Fraction.COLOR_BLUFOR, Fraction.COLOR_OPFOR, Fraction.COLOR_BLUFOR_LIGHT, Fraction.COLOR_OPFOR_LIGHT,
Fraction.COLOR_BLUFOR_DARK, Fraction.COLOR_OPFOR_DARK, Fraction.COLOR_BLUFOR_GREY, Fraction.COLOR_OPFOR_GREY]
};
readonly labels = {
points: 'stats.fraction.select.points',
budget: 'stats.fraction.select.budget',
kill: 'stats.fraction.select.kills',
friendlyFire: 'stats.fraction.select.friendly.fire',
vehicle: 'stats.fraction.select.vehicle.kills',
transport: 'stats.fraction.select.air.transport',
revive: 'stats.fraction.select.revive',
stabilize: 'stats.fraction.select.stabilize',
flag: 'stats.fraction.select.flag'
};
readonly labelsAsString = Object.keys(this.labels).map((key) => this.labels[key]);
labels;
labelsKeys;
lineChartLabel: string;
@ -87,8 +78,12 @@ export class FractionStatsComponent implements OnInit, OnChanges {
kill: false,
revive: false,
transport: false,
flag: false
flag: false,
playerCount: false
};
this.initializeToggleButtons();
Object.assign(this, [this.lineChartData, this.areaChartData]);
this.activeChartSelect = this.labels.points;
@ -99,6 +94,42 @@ export class FractionStatsComponent implements OnInit, OnChanges {
}
}
/**
* show only labels for for data that is available,
* to not end up with empty charts in old battles
*/
initializeToggleButtons() {
const newLabels = {};
if (this.logData.points && this.logData.points.length > 0) {
newLabels['points'] = 'stats.fraction.select.points';
}
if (this.logData.budget && this.logData.budget.length > 0) {
newLabels['budget'] = 'stats.fraction.select.budget';
}
if (this.logData.kill && this.logData.kill.length > 0) {
newLabels['kill'] = 'stats.fraction.select.kills';
newLabels['friendlyFire'] = 'stats.fraction.select.friendly.fire';
}
if (this.logData.vehicle && this.logData.vehicle.length > 0) {
newLabels['vehicle'] = 'stats.fraction.select.vehicle.kills';
}
if (this.logData.transport && this.logData.transport.length > 0) {
newLabels['transport'] = 'stats.fraction.select.air.transport';
}
if (this.logData.revive && this.logData.revive.length > 0) {
newLabels['revive'] = 'stats.fraction.select.revive';
newLabels['stabilize'] = 'stats.fraction.select.stabilize';
}
if (this.logData.flag && this.logData.flag.length > 0) {
newLabels['flag'] = 'stats.fraction.select.flag';
}
if (this.logData.playerCount && this.logData.playerCount.length > 0) {
newLabels['playerCount'] = 'stats.fraction.select.player.count';
}
this.labels = newLabels;
this.labelsKeys = Object.keys(this.labels);
}
selectChart(newSelection) {
this.activeChartSelect = newSelection;
if (this.activeChartSelect !== this.labels.flag) {
@ -136,6 +167,10 @@ export class FractionStatsComponent implements OnInit, OnChanges {
this.initTransportData();
this.lineChartData = this.tmpTransportData;
break;
case this.labels.playerCount:
this.initPlayerCountData();
this.lineChartData = this.tmpPlayerCountData;
break;
}
} else {
this.initFlagHoldData();
@ -347,6 +382,20 @@ export class FractionStatsComponent implements OnInit, OnChanges {
this.initialized.transport = true;
}
initPlayerCountData() {
if (this.initialized.playerCount) {
return;
}
this.logData.playerCount.forEach(playerCountEntry => {
this.tmpPlayerCountData[0].series.push(
ChartUtils.getSeriesEntry(new Date(playerCountEntry.time), playerCountEntry.countBlufor));
this.tmpPlayerCountData[1].series.push(
ChartUtils.getSeriesEntry(new Date(playerCountEntry.time), playerCountEntry.countOpfor));
});
this.initialized.playerCount = true;
this.addFinalTimeData(this.tmpPlayerCountData);
}
initFlagHoldData() {
if (this.initialized.flag) {
return;
@ -387,6 +436,7 @@ export class FractionStatsComponent implements OnInit, OnChanges {
this.tmpReviveData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
this.tmpStabilizeData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
this.tmpFlagCaptureData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
this.tmpPlayerCountData = ChartUtils.getMultiDataArray(Fraction.BLUFOR, Fraction.OPFOR);
[this.tmpKillData, this.tmpFrienlyFireData, this.tmpVehicleData, this.tmpReviveData, this.tmpStabilizeData,
this.tmpTransportData].forEach(tmp => {

View File

@ -10,7 +10,7 @@
.mat-header-row {
width: 1058px;
position: fixed;
position: absolute;
z-index: 100;
}
@ -27,8 +27,9 @@
}
.mat-column-kill, .mat-column-friendlyFire, .mat-column-revive, .mat-column-flagTouch, .mat-column-vehicleLight,
.mat-column-vehicleHeavy, .mat-column-vehicleAir, .mat-column-death, .mat-column-respawn, .mat-column-interact {
flex: 0 0 75px;
.mat-column-vehicleHeavy, .mat-column-vehicleAir, .mat-column-travelDistance, .mat-column-driverDistance,
.mat-column-death, .mat-column-respawn, .mat-column-interact {
flex: 0 0 62px;
}
:host /deep/ .mat-table .mat-icon {

View File

@ -52,6 +52,12 @@ export class ScoreboardComponent implements OnChanges {
ngOnChanges(changes: SimpleChanges) {
if (changes.war) {
this.war.players.forEach(player => {
// meters to kilometer or fill with null, since optional
player.travelDistance = player.travelDistance ? Math.round(player.travelDistance / 1000) : 0;
player.driverDistance = player.driverDistance ? Math.round(player.driverDistance / 1000) : 0;
});
this.rows = changes.war.currentValue.players;
this.currentSort.active = 'kill';
this.sortScoreboardData(this.currentSort);

View File

@ -0,0 +1,37 @@
.chart-select-group {
display: flex;
width: fit-content;
margin: auto;
}
:host /deep/ mat-button-toggle {
color: #666666;
background: #e7e7e7;
}
:host /deep/ mat-button-toggle:hover {
background: #afafaf;
}
:host /deep/ mat-button-toggle.mat-button-toggle-checked {
background: #ffffff;
}
:host /deep/ label.mat-button-toggle-label {
margin: 2px 0;
}
:host /deep/ div.mat-button-toggle-label-content {
line-height: 25px;
margin-bottom: 0;
font-weight: normal;
}
.chart-container {
width: 95%;
margin: 2%;
min-width: 900px;
height: 50vh;
padding: 15px;
float: left;
}

View File

@ -0,0 +1,46 @@
<div class="fade-in" style="border-top: 1px solid #dadada; padding-top:25px;" xmlns="http://www.w3.org/1999/html">
<mat-button-toggle-group class="chart-select-group"
#group="matButtonToggleGroup"
[(ngModel)]="activeChartSelect"
(change)="selectChart(group.value)">
<mat-button-toggle *ngFor="let label of labelsAsString" value="{{label}}">
{{label | translate}}
</mat-button-toggle>
</mat-button-toggle-group>
<div class="chart-container" *ngIf="showBarChart">
<ngx-charts-bar-vertical
[results]="barChartData"
[scheme]="colorScheme"
[gradient]="gradient"
[xAxis]="xAxis"
[yAxis]="yAxis"
[legend]="legend"
[legendTitle]="legendTitle"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[yAxisLabel]="barChartLabel"
[barPadding]="2"
[roundDomains]="roundDomains">
</ngx-charts-bar-vertical>
</div>
<div class="chart-container" *ngIf="!showBarChart">
<ngx-charts-line-chart
[results]="lineChartData"
[scheme]="colorScheme"
[gradient]="gradient"
[xAxis]="xAxis"
[yAxis]="yAxis"
[legend]="legend"
[legendTitle]="legendTitle"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[yAxisLabel]="lineChartLabel"
[autoScale]="autoscale"
[timeline]="timeline"
[roundDomains]="roundDomains">
</ngx-charts-line-chart>
</div>
</div>

View File

@ -0,0 +1,203 @@
import {Component, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core';
import {War} from '../../../models/model-interfaces';
import {TranslateService} from '@ngx-translate/core';
import {ChartUtils} from '../../../utils/chart-utils';
@Component({
selector: 'cc-server-statistics',
templateUrl: './server-stats.component.html',
styleUrls: ['./server-stats.component.css', '../../../style/list-entry.css', '../../../style/hide-scrollbar.css']
})
export class ServerStatsComponent implements OnInit, OnChanges {
@ViewChild('overview') private overviewContainer: ElementRef;
@Input() war: War;
@Input() performanceData: any;
startDateObj: Date;
public activeChartSelect: string;
showBarChart = true;
barChartData: any[] = [];
lineChartData: any[] = [];
tmpSingleAvg;
tmpSingleMin;
tmpAvgTimeline;
tmpMinTimeline;
tmpServerTimeline;
barChartLabel: string;
lineChartLabel: string;
readonly labels = {
singleAvg: 'stats.performance.select.single.avg',
singleMin: 'stats.performance.select.single.min',
avgTimeline: 'stats.performance.select.timeline.avg',
minTimeline: 'stats.performance.select.timeline.min',
serverFps: 'stats.performance.select.timeline.server',
};
readonly labelsAsString = Object.keys(this.labels)
.map((key) => this.labels[key]);
lineChartSeriesLabels: string[];
gradient = false;
yAxis = true;
xAxis = true;
legend = false;
legendTitle = false;
showXAxisLabel = false;
showYAxisLabel = true;
autoscale = true;
timeline = false;
roundDomains = true;
colorScheme = {
name: 'nightLights',
selectable: false,
group: 'Ordinal',
domain: [
'#4e31a5', '#9c25a7', '#3065ab', '#57468b', '#904497', '#46648b',
'#32118d', '#a00fb3', '#1052a2', '#6e51bd', '#b63cc3', '#6c97cb', '#8671c1', '#b455be', '#7496c3'
]
};
constructor(private translate: TranslateService) {
}
ngOnInit() {
this.setBarChartLabel(this.labels.singleAvg);
}
ngOnChanges(changes: SimpleChanges) {
if ((changes.war || changes.performanceData) && this.performanceData) {
this.translate.get(['stats.performance.select.timeline.label.minimum',
'stats.performance.select.timeline.label.average',
'stats.performance.select.timeline.label.maximum']).subscribe((res) => {
const resValues = Object.keys(res).map(val => res[val]);
this.initializeChartData(resValues[2], resValues[0], resValues[1]);
});
Object.assign(this, [this.barChartData]);
this.activeChartSelect = this.labels.singleAvg;
}
}
selectChart(newSelection) {
this.activeChartSelect = newSelection;
if (this.activeChartSelect === this.labels.singleAvg || this.activeChartSelect === this.labels.singleMin) {
this.showBarChart = true;
this.setBarChartLabel(this.activeChartSelect);
switch (this.activeChartSelect) {
case this.labels.singleAvg:
this.barChartData = this.tmpSingleAvg;
break;
case this.labels.singleMin:
this.barChartData = this.tmpSingleMin;
break;
}
} else {
this.showBarChart = false;
this.setLineChartLabel(this.activeChartSelect);
switch (this.activeChartSelect) {
case this.labels.avgTimeline:
this.lineChartData = this.tmpAvgTimeline;
break;
case this.labels.minTimeline:
this.lineChartData = this.tmpMinTimeline;
break;
case this.labels.serverFps:
this.lineChartData = this.tmpServerTimeline;
}
}
}
initializeChartData(labelMax: string, labelMin: string, labelAvg: string) {
this.tmpAvgTimeline = ChartUtils.getMultiDataArray(labelMax, labelAvg, labelMin);
this.tmpMinTimeline = ChartUtils.getMultiDataArray(labelMax, labelAvg, labelMin);
this.tmpServerTimeline = ChartUtils.getMultiDataArray(labelAvg, labelMin);
const diffMs = (new Date(this.war.endDate).getTime() - new Date(this.war.date).getTime());
const warDurationMinutes = Math.round(diffMs / 60000);
const dateObj = new Date(this.war.date);
dateObj.setHours(0);
dateObj.setMinutes(1);
this.tmpSingleAvg = [];
this.tmpSingleMin = [];
const maxAvgIdx = Math.min(this.performanceData.map(p => p.avgFps.length)
.sort((a, b) => b - a)[0], warDurationMinutes);
const maxMinIdx = Math.min(this.performanceData.map(p => p.avgFps.length)
.sort((a, b) => b - a)[0], warDurationMinutes);
let tmpAvgArray = new Array(maxAvgIdx).fill(0);
const tmpAvgMin = new Array(maxAvgIdx).fill(1000);
const tmpAvgMax = new Array(maxAvgIdx).fill(0);
let tmpMinArray = new Array(maxMinIdx).fill(0);
const tmpMinMin = new Array(maxMinIdx).fill(1000);
const tmpMinMax = new Array(maxMinIdx).fill(0);
this.performanceData.forEach((entry) => {
if (entry.entityName !== 'SERVER') {
// PLAYER AVERAGE TIMELINE DATA
for (let i = 0; i < entry.avgFps.length && i < tmpAvgArray.length; i++) {
tmpAvgArray[i] = tmpAvgArray[i] + entry.avgFps[i];
tmpAvgMin[i] = Math.round(Math.min(tmpAvgMin[i], entry.avgFps[i]));
tmpAvgMax[i] = Math.round(Math.max(tmpAvgMax[i], entry.avgFps[i]));
}
// PLAYER MINIMUM TIMELINE DATA
for (let i = 0; i < entry.minFps.length && i < tmpMinArray.length; i++) {
tmpMinArray[i] = tmpMinArray[i] + entry.minFps[i];
tmpMinMin[i] = Math.round(Math.min(tmpMinMin[i], entry.minFps[i]));
tmpMinMax[i] = Math.round(Math.max(tmpMinMax[i], entry.minFps[i]));
}
} else {
// SERVER TIMELINE DATA
for (let i = 0; i < entry.avgFps.length && i < warDurationMinutes; i++) {
const currDate = new Date(dateObj.getTime() + i * 60000);
this.tmpServerTimeline[0].series.push(ChartUtils.getSeriesEntry(currDate, entry.avgFps[i]));
this.tmpServerTimeline[1].series.push(ChartUtils.getSeriesEntry(currDate, entry.minFps[i]));
}
}
this.tmpSingleAvg.push({
name: entry.entityName,
value: entry.singleAvgFps
});
this.tmpSingleMin.push({
name: entry.entityName,
value: entry.singleMinFps
});
});
tmpAvgArray = tmpAvgArray.map(x => Math.round(x / this.performanceData.length));
for (let i = 0; i < tmpAvgArray.length; i++) {
const currDate = new Date(dateObj.getTime() + i * 60000);
this.tmpAvgTimeline[0].series.push(ChartUtils.getSeriesEntry(currDate, tmpAvgMax[i]));
this.tmpAvgTimeline[1].series.push(ChartUtils.getSeriesEntry(currDate, tmpAvgArray[i]));
this.tmpAvgTimeline[2].series.push(ChartUtils.getSeriesEntry(currDate, tmpAvgMin[i]));
}
tmpMinArray = tmpMinArray.map(x => Math.round(x / this.performanceData.length));
for (let i = 0; i < tmpMinArray.length; i++) {
const currDate = new Date(dateObj.getTime() + i * 60000);
this.tmpMinTimeline[0].series.push(ChartUtils.getSeriesEntry(currDate, tmpMinMax[i]));
this.tmpMinTimeline[1].series.push(ChartUtils.getSeriesEntry(currDate, tmpMinArray[i]));
this.tmpMinTimeline[2].series.push(ChartUtils.getSeriesEntry(currDate, tmpMinMin[i]));
}
this.tmpSingleAvg.sort((a, b) => a.value - b.value);
this.tmpSingleMin.sort((a, b) => a.value - b.value);
this.barChartData = this.tmpSingleAvg;
}
setLineChartLabel(i18n: string) {
this.translate.get(i18n).subscribe((translated) => {
this.lineChartLabel = translated;
});
}
setBarChartLabel(i18n: string) {
this.translate.get(i18n).subscribe((translated) => {
this.barChartLabel = translated;
});
}
}

View File

@ -16,7 +16,7 @@ form.tab-control {
}
span.tab-control {
margin: 4px 67px;
margin: 4px 30px 4px 55px;
padding: 4px 16px;
}
@ -39,13 +39,21 @@ span.tab-control {
vertical-align: middle;
}
:host/deep/.mat-icon-stats-performance g {
stroke: #666666;
}
.nav-tabs {
width: 920px;
width: 1000px;
margin: auto;
clear: both;
border-bottom: 0;
}
.nav-tab-hidden {
visibility: hidden;
}
.nav-tabs > li > a {
background: #e7e7e7;
border: 1px solid #dadada;
@ -56,7 +64,7 @@ span.tab-control {
}
.nav-tabs > li:last-child {
margin-left: 70px;
margin-left: 65px;
}
.nav-link {

View File

@ -2,9 +2,11 @@
<div class="war-header-container">
<div class="pull-left head-field" style="width: 250px">
<h4>{{'stats.scoreboard.standings' | translate}}</h4>
<span [style.color]="fraction.COLOR_BLUFOR" style="font-weight: bold; margin-right: 10px">{{fraction.BLUFOR}} {{war.ptBlufor}}</span>
<span [style.color]="fraction.COLOR_BLUFOR"
style="font-weight: bold; margin-right: 10px">{{fraction.BLUFOR}} {{war.ptBlufor}}</span>
<span style="font-size: x-large">|</span>
<span [style.color]="fraction.COLOR_OPFOR" style="font-weight: bold; margin-left: 10px;">{{war.ptOpfor}} {{fraction.OPFOR}}</span>
<span [style.color]="fraction.COLOR_OPFOR"
style="font-weight: bold; margin-left: 10px;">{{war.ptOpfor}} {{fraction.OPFOR}}</span>
</div>
<div class="pull-left head-field " style="padding-left: 100px;">
@ -48,6 +50,14 @@
{{'stats.scoreboard.tab.player' | translate}}
</a>
</li>
<li class="nav-item"
[ngClass]="{active : tab === 3,'nav-tab-hidden' : war && war.players[0] && !war.players[0].performance}"
(click)="switchTab(3)">
<a class="nav-link">
<mat-icon svgIcon="stats-performance" class="mat-icon-stats-performance"></mat-icon>
{{'stats.scoreboard.tab.performance' | translate}}
</a>
</li>
<li>
<div *ngIf="tab === 0">
<form class="pull-left tab-control">
@ -100,6 +110,11 @@
[playerName]="playerDetailName"
(switchTab)="switchTab($event)">
</campaign-player-detail>
<cc-server-statistics
*ngIf="tab === 3"
[war]="war"
[performanceData]="performanceData">
</cc-server-statistics>
</div>
</div>

View File

@ -23,14 +23,18 @@ export class WarHeaderComponent implements OnInit {
logData;
fractionStatsInitialized: boolean;
performanceData;
performanceStatsInitialized: boolean;
singlePlayerView: number;
playerDetailName: string;
tab: number;
fractionStatsInitialized: boolean;
fractionFilterSelected: string;
playerChart: any[] = [];
@ -70,6 +74,12 @@ export class WarHeaderComponent implements OnInit {
this.fractionStatsInitialized = true;
});
}
if (index === 3 && !this.performanceStatsInitialized) {
this.logsService.getPerformanceLogs(this.war._id).subscribe(log => {
this.performanceData = log;
this.performanceStatsInitialized = true;
});
}
}
/**

View File

@ -1,5 +1,21 @@
export class PlayerUtils {
// TODO: drop this tmp collection, excluding player transport stats from campaign detail page and highscore page,
// adding valid processing there
public static readonly tmpAttributeDisplayNames = [
{prop: 'name', head: 'stats.scoreboard.header.player'},
{prop: 'fraction', head: 'stats.scoreboard.header.fraction'},
{prop: 'kill', head: 'stats.scoreboard.header.kill'},
{prop: 'friendlyFire', head: 'stats.scoreboard.header.friendly.fire'},
{prop: 'revive', head: 'stats.scoreboard.header.revive'},
{prop: 'flagTouch', head: 'stats.scoreboard.header.capture'},
{prop: 'vehicleLight', head: 'stats.scoreboard.header.vehicle.light'},
{prop: 'vehicleHeavy', head: 'stats.scoreboard.header.vehicle.heavy'},
{prop: 'vehicleAir', head: 'stats.scoreboard.header.vehicle.air'},
{prop: 'death', head: 'stats.scoreboard.header.death'},
{prop: 'respawn', head: 'stats.scoreboard.header.respawn'},
];
public static readonly attributeDisplayNames = [
{prop: 'name', head: 'stats.scoreboard.header.player'},
{prop: 'fraction', head: 'stats.scoreboard.header.fraction'},
@ -10,8 +26,10 @@ export class PlayerUtils {
{prop: 'vehicleLight', head: 'stats.scoreboard.header.vehicle.light'},
{prop: 'vehicleHeavy', head: 'stats.scoreboard.header.vehicle.heavy'},
{prop: 'vehicleAir', head: 'stats.scoreboard.header.vehicle.air'},
{prop: 'travelDistance', head: 'stats.scoreboard.header.travel.distance'},
{prop: 'driverDistance', head: 'stats.scoreboard.header.driver.distance'},
{prop: 'death', head: 'stats.scoreboard.header.death'},
{prop: 'respawn', head: 'stats.scoreboard.header.respawn'}
{prop: 'respawn', head: 'stats.scoreboard.header.respawn'},
];
public static isSteamUUID(input: string): boolean {

View File

@ -27,6 +27,17 @@
"stats.fraction.select.revive": "Revive",
"stats.fraction.select.stabilize": "Stabilisiert",
"stats.fraction.select.flag": "Flaggenbesitz",
"stats.fraction.select.player.count": "Spieleranzahl",
"stats.performance.select.single.avg": "Spieler FPS Durchschnitt",
"stats.performance.select.single.min": "Spieler FPS Minimum",
"stats.performance.select.timeline.avg": "Verlauf FPS Durchschnitt",
"stats.performance.select.timeline.min": "Verlauf FPS Minimum",
"stats.performance.select.timeline.server": "Server FPS",
"stats.performance.select.timeline.label.minimum": "Minimum",
"stats.performance.select.timeline.label.average": "Mittelwert",
"stats.performance.select.timeline.label.maximum": "Maximum",
"stats.player.detail.headline": "Kampagnendetails - {{name}}",
"stats.player.detail.button.back": "Zurück",
@ -41,6 +52,7 @@
"stats.scoreboard.tab.scoreboard": "Scoreboard",
"stats.scoreboard.tab.fractions": "Fraktionen",
"stats.scoreboard.tab.player": "Spieler",
"stats.scoreboard.tab.performance": "Performance",
"stats.scoreboard.fraction.filter.all": "Alle",
"stats.scoreboard.header.player": "Spieler",
"stats.scoreboard.header.fraction": "Fraktion",
@ -53,6 +65,8 @@
"stats.scoreboard.header.vehicle.air": "Fahrzeug (Luft)",
"stats.scoreboard.header.death": "Tode",
"stats.scoreboard.header.respawn": "Respawn",
"stats.scoreboard.header.travel.distance": "Passagier Flugdistanz (km)",
"stats.scoreboard.header.driver.distance": "Pilot Flugdistanz (km)",
"stats.scoreboard.button.detail": "Kampagnenstatistik für {{name}}",
"stats.highscore.filter.placholder": "Spielername (mehrere mit '&' trennen)",

View File

@ -35,6 +35,16 @@
"stats.fraction.select.revive": "Revive",
"stats.fraction.select.stabilize": "Stabilized",
"stats.fraction.select.flag": "Flag Possession",
"stats.fraction.select.player.count": "Player Count",
"stats.performance.select.single.avg": "Player FPS Average",
"stats.performance.select.single.min": "Player FPS Minimum",
"stats.performance.select.timeline.avg": "Timeline FPS Average",
"stats.performance.select.timeline.min": "Timeline FPS Minimum",
"stats.performance.select.timeline.server": "Server FPS",
"stats.performance.select.timeline.label.minimum": "Minimum",
"stats.performance.select.timeline.label.average": "Average",
"stats.performance.select.timeline.label.maximum": "Maximum",
"stats.player.detail.headline": "Campaign Details - {{name}}",
"stats.player.detail.button.back": "Back",
@ -49,6 +59,7 @@
"stats.scoreboard.tab.scoreboard": "Scoreboard",
"stats.scoreboard.tab.fractions": "Fractions",
"stats.scoreboard.tab.player": "Player",
"stats.scoreboard.tab.performance": "Performance",
"stats.scoreboard.fraction.filter.all": "All",
"stats.scoreboard.header.player": "Player",
"stats.scoreboard.header.fraction": "Fraction",
@ -61,6 +72,8 @@
"stats.scoreboard.header.vehicle.air": "Vehicle (Air)",
"stats.scoreboard.header.death": "Death",
"stats.scoreboard.header.respawn": "Respawn",
"stats.scoreboard.header.travel.distance": "Passenger Travel Distance (km)",
"stats.scoreboard.header.driver.distance": "Pilot Travel Distance (km)",
"stats.scoreboard.button.detail": "Campaign statistics for {{name}}",
"stats.highscore.filter.placholder": "Player Name (separate multiple using '&')",

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="5.3327in" height="5in" version="1.1" viewBox="0 0 512 490" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#000" stroke-width="20">
<path id="outline"
d="m328.5 435.5 71.5 0.5 3.5 28.5-289-1.5 10-28.5 62.5 0.5s11-37.5 12.72-53.36c-82.82 0.2-152.22 0.36-152.22 0.36-39.96-4.54-37-34.5-37-34.5l-2-282.5s-0.32-18.24 7-26c9-9.55 26-9 26-9s426.5-1 426.5-1c39.96 4.54 37 34.5 37 34.5l2 282.5s-1.22 15.25-9 23.5c-8.67 9.2-24 11.5-24 11.5s-71.37 0.17-155.73 0.37c8.23 38.63 10.23 54.13 10.23 54.13z"/>
</g>
<g fill="none" stroke="#000" stroke-width="14">
<path id="inline" d="m457 79v230h-400v-233h400z"/>
</g>
<g fill="none" stroke="#000" stroke-width="30">
<path id="arrow"
d="m133.68 258.51 59.2-52.57 54.05 49.13 131.67-131.18m-47.66-0.98s38.33-4.18 48.64-0.49c5.9 5.65-0.24 49.62-0.24 49.62"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 909 B

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6.9in"
height="6.9in"
version="1.1"
viewBox="0 0 500 500"
id="svg9"
sodipodi:docname="driver-distance.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata15">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs13" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1053"
id="namedview11"
showgrid="false"
inkscape:zoom="0.71256038"
inkscape:cx="128.73924"
inkscape:cy="570.81484"
inkscape:window-x="425"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg9" />
<path
id="Selection"
d="m46 299c-1.8 0.83-2.8 1.1-4.2 2.8-3.4 3.8-4 11-0.42 16 2.4 3.3 6.3 4.9 7.7 6.2 2.3 2.3 3.4 7.3 1.2 9.8-3.6 4.1-12-0.85-14-14-2.3-14 1.5-22 8-30l1.8 9.5zm410 84-23-12s-142-49-145-51c0 0-14-7.5-16-9.5-2.8-2.8-4.8-7.9-9.9-10-5.5-2.2-12 1.4-19-2.8l-111-105s-5.5-0.74-5-2.5l-0.9 4.4c6.1 3.8 106 95 112 103l-150-78c2 6.1 3.1 6.4 7.5 8.6l137 72c5.7 3 13 7.3 17 13l-4.9-3.3c-4-2-20-5.5-24-4.3-2.8 0.91-21 14-22 14-1.9 0.14-7.8-3.2-9.9-4.3-2.6 9.5-3.6 8.2-10 10l-29 7s-28-6.8-31-9c-14-8.3-15-2.3-27-5.3-2.6-0.91-8.6-2.5-11-5.3-1.7-1.9-2.1-6.2-2.6-9 0 0-17-98-20-102-1.8-2.6-22-14-22-14s1.4 74 0.23 77c-0.82 2.5-23 34-22 40 2.1 11 14 30 20 37 3 2.9 32 19 36 18 2.6-0.88 7.2-11 8.7-14 6.2 3.1 22 11 27 17 3.8 4.9 2.5 13 5 18 1.7 3.4 12 8.2 14 7.1 4.7-2.5 3.5-10 11-5.8l58 41 79 37s69 23 77 23c2.4 0.018 10-2.8 11-4.1 11-9.4-4.3-25-6.2-29 0 0-26-51-34-59-6.9-6.6-19-12-27-16 1.8-9-17-32-17-32-1.7-2.8-1.3-7.1-2.5-11-1.2-3.4-3.1-4.9-5.4-6.8 2.7-9.9 8.4-2.9 14-0.4l64 26 0.45-2.2s-42-17-47-22l142 52 14 2.5z" />
<g
id="g7"
style="fill-rule:evenodd">
<path
d="m 360,0 v 70 l 70,68 -70,68 v 69 L 502,137 Z"
id="path3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
d="m 262,2.7 v 70 l 70,68 -70,68 v 69 l 142,-138 z"
id="path5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1 @@
<svg width="19in" height="19in" version="1.1" viewBox="0 0 1368 1368" xmlns="http://www.w3.org/2000/svg"><path id="Auswahl" transform="scale(.75)" d="m1375 0c-11 7.3-22 14-32 17-456 101-935 160-1344 256v57c354-82 743-156 1074-209 138-18 276-53 363-47 2.5-0.16 6.8-0.39 9.1 0 8.5 3.5 9.5 13 19 16 4.1 2 11 0.36 16 0l33-6.5c3.7-0.69 13-2.6 16-1.3 10 4 2.7 20 7.9 29 2.9 6 11 7.2 13 13 2.1 5.5-1.6 14-3.3 19-4 11-12 37-19 45-8 9.3-39 23-52 31-20 11-51 39-69 55-16 14-18 10-24 17-11 15-14 33-21 48-19 30-30 55-40 88-11 28-18 57-24 87-1.6 5.9-2.9 15-8.3 19-6.7 6.3-21-1.3-23 16-0.4 6.4 1.1 12 5.7 16 5.2 4.4 13 2.4 13 12-11 52-6.3 104-12 151-5.3 0-21 0.93-27-1.9-5.3-4-17-22-21-28-16-21-33-43-52-61-9.7-10-6.1-14-11-20-4-5.7-13-6.2-20-6.4v11l-29-4.3-25 6c-8 0.27-16-6.7-28-5.2-15 2-17 17-27 11-12-6.7-6.6-15-6.3-24 0.27-6.4-3-9.5-3.3-15l1.5-11-2.7-17c-1.9-5.1-7.5-4-12-10l-4.7-9.9c-2.7-4-21-17-25-17-5.5-0.67-10 4.8-16 6l-1.8-0.18-3.3 1.3c-7.1 2.2-9.3 3.6-13 7.8l-31 5.5c-1.6-3.2-2.9-6.8-7.2-7.5-4-0.67-8.3 3.6-11 5.9-11 8.9-10 8.8-20 19-2.8 2.8-7.1 6.4-9.1 9.9-5.3 8.9 4.1 12 2.7 21-1.3 6.7-19 35-17 44 1.9 13 14 21 13 36 9.3 3.5 8 5.7 15 9.2 4.7 2.3 7.5 1.3 15 5.2 14 7.7 13 11 20 17 5.2 4.3 11 5.7 13 13 1.9 6.7-3.6 14-5.9 21l9.2 1.9 3.6-33 33 19h20l11-13c-1.6 8-6.7 22-4.7 29 2 6.8 7.1 7.6 9.7 16l3.7 25c1.9 6.1 6 10 4.3 16-2.7 6.7-17 18-23 23-25 22-21 14-36 24l-20 17c-9.3 5.5-8-3.6-24 11 0.35-3.2 0.45-8 0-11-8-25-40 3.5-48 4.8-5.6 1.1-10-4.2-16-3.9-3.3 0.13-6.4 2-9.1 4-19 15-2.4 24 5.5 37 6.7 12 13 8.3 25 9.2l-6.8 15-49 45c-7.5-10-16-0.67-20 7.3-11 2.7-9.7 13-11 21l-2.5 13c0.13 4.3 2.3 7.3 1.5 11-1.3 6.7-12 13-8 20 6.7 10 20-15 28-4.4 3.3 5.3 7.2 23 4.3 28-3.2 4.5-11 8.8-13 17-2.7 10 8 23 19 23 8-0.13 9.1-5.6 19-6.5-4.9 15-4.8 24-3.5 39v15l17 64 2.3 33c-2.4 19-6.7 11-4.9 36 0.93 13-9.4 19-10 29-0.67 6.7 8.1 17 8.4 33v21c0.53 11 5.2 25 1.9 35-10 21-29 27-46 36-21 9.2-19 17-21 38-12-0.8-19 5.3-28 11 0.27 13-4.5 17 3.6 29 8 11 21 15 33 17 27 4.7 44 5.5 69-6.1 13-6.7 27-23 40-25 6.8-0.93 9.9 2.3 15 3.2 6.7 1.1 14-3.5 20-6.1 19-9.3 31-11 29-35 0.13-5.9-2-14 0-19 1.6-5.2 6.5-6.9 9.1-11 1.7-4 0.75-13 0-17-1.5-15-15-37-15-44 0.4-6.7 6.9-11 9.9-20l5.2-25 8.1-28 4.3-25v-19l3.5-19-2.9-35c0.27-17-6.7-36-9.9-53 28 1.3 35 15 55 16 41-6.7 78-10 121-15 67-3.6 114-12 169-43 4-2 13-7.7 17-6.9 8 1.3 16 25 21 33l43 59c8 8 27 23 31 32l-24 10c-37 17-61 33-92 60-20 14-32 35-52 45-4-21-27-19-32-11-10 17 10 39 2.4 53l-48 65c-9.3 16-29 48-37 64l-16 33-8.1 19c-9.3 16-16 13-25 29l-43 95c-8 19-15 37-27 53-60-2.4-51-6.4-76 13-5.5 11-10 17-12 28l0.99 39h113c3.7 0 10 0.4 13-1.9 3.7-2.7 11-29 13-35l16-43c8-15 38-52 49-65l47-55 16-20 15-15 48-56c16-16 29-25 32-28l7.3-10c3.6-5.1 8.8-10 13-15 17-17 35-31 53-45 32-27 45-36 83-55 62-31 49-30 104-40 48-9.6 44-3.8 88-3.3 55 23 119 26 174 28v-1279c1.2-64-0.46-76 0-94zm-3.1 431c4.6 30-12 55-19 81l-10 17c-2.1 8 8.2 14 8.7 24 0.53 13-10 24-7.6 43-16-0.27-12 1.2-25 7.3l4.3-29c7.6-18 29-144 49-143zm-51 182c7.7 9.3 13 8.4 15 13 1.2 15-3.9 30-6.7 44-1.5 3.7-4.1 7.7-8.5 7.9-7.3 0-7.5-9.6-7.1-15l0.68-1.2c1.1-15 0.8-37 6.9-49zm-296 241c1.5 21 7.5 19 10 29 1.2 3.9 0.8 8.5-3.5 10-6.1 2.7-9.6-4.5-16-7.7-7.6-3.3-15-3.1-22-2.7 5.3-20 12-24 31-29zm-66 104c7.6 9.3 20 18 0 24zm508 303c1.1 0 2.1 0.076 3 0.24 8 1.3 35 19 44 24 5.3 3.6 22 11 24 16 5.3 13-12 17-20 20-53 20-104 49-143 81v-1.1c-11 9.3-59 47-69 52-6.7-11-17-33-21-45-1.7-5.3-5-15-4-20 0.67-6.1 8.4-13 13-17l53-48c28-23 60-43 95-56 7-2.3 17-5.9 25-5.8zm-218 163c7.1 16 9.1 22 12 35 2.8 9.3 9.2 25 7.2 35-2.7 8-21 27-28 35l-67 76c-9.3 9.3-20 27-32 31 2.1-8 6.9-16 7.7-24v-11c1.3-11 16-42 21-53l45-79z"/></svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,130 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 67.1" style="enable-background:new 0 0 100 67.1;" xml:space="preserve">
<g>
<path d="M68.5,21.6c-0.1,0-0.2,0.1-0.3,0.2C68.3,21.6,68.4,21.6,68.5,21.6z"/>
<path d="M99.9,5.6c-0.4-0.1-0.6,0-0.9,0.2c-0.9,0.4-1.8,0.8-2.8,1.2c-0.9,0.4-1.8,0.8-2.7,1.3c-0.8,0.4-1.7,0.8-2.5,1.1
c-0.9,0.5-1.7,0.8-2.6,1.3c-0.9,0.5-1.8,0.8-2.7,1.3c-0.7,0.3-1.3,0.6-2,1c-0.8,0.4-1.7,0.8-2.5,1.2c-0.8,0.4-1.7,0.8-2.5,1.2
c-0.8,0.3-1.6,0.8-2.4,1.2c-0.8,0.4-1.7,0.8-2.5,1.2c-0.7,0.3-1.4,0.6-2.1,1c-0.3,0.2-0.6,0.4-0.9,0c-0.1-0.1-0.2,0-0.3,0
c-0.5,0.1-1,0.2-1.5,0.2c-0.8,0.1-1.5,0.2-2.2,0.3c-1,0.2-1.9,0.3-2.8,0.4c-0.8,0.1-1.4,0.3-2.2,0.4c-0.7,0.1-1.4,0.2-2.1,0.3
c-1.4,0.3-2.7,0.5-4.1,0.9c-0.7,0.2-1.5,0.3-2.3,0.5C52,22.2,51,22.6,50,22.7c-0.1,0-0.1,0-0.2,0.1l0,0c-0.1,0-0.3,0.1-0.4,0.2
c-0.5,0.2-1,0.3-1.5,0.3c0.2-0.2,0.1-0.4,0.3-0.4c0.4-0.2,0.7-0.4,0.9-0.8c0.5-0.7,1-1.2,1.6-1.8c0.2-0.4,0.7-0.5,1.1-0.7
c0.4-0.1,0.9-0.2,1.2-0.6c0.8-0.8,1.6-1.6,2.4-2.2c0.9-0.9,1.9-1.9,2.8-2.7c1.1-1,2.3-2,3.4-3s2.2-2,3.3-2.9c0.7-0.7,1.6-1.3,2.3-2
c0.7-0.5,1.2-1,1.9-1.5s1.3-1.1,1.9-1.7c0.4-0.3,0.7-0.7,1.1-1c0.7-0.5,1.2-1,1.8-1.4c0.2-0.2,0.4-0.2,0.3-0.4
c-0.1-0.2-0.3,0-0.6-0.1c-0.8,0.1-1.6,0.1-2.5,0.1c-0.1,0-0.3,0.1-0.4,0.1c-0.4,0.2-0.7,0.5-1.1,0.7c-0.5,0.2-1,0.6-1.6,1
c-0.2,0.2-0.5,0.2-0.7,0.4c-0.8,0.7-1.7,1.5-2.5,2.2c-0.5,0.8-1.2,1.5-2,2c-0.8,0.7-1.7,1.5-2.6,2.3c-0.7,0.5-1.2,1.1-1.7,1.6
c-1,1-2,1.9-3,2.7c-0.6,0.6-1.3,1.1-1.9,1.8c-1,1-1.9,2-2.9,2.8c-1.2,1.1-2.2,2.3-3.4,3.5c-0.2,0.2-0.4,0.6-0.8,0.5
c-0.2,0-0.6,0.2-0.7-0.1c-0.1-0.2-0.2-0.3-0.2-0.5c-0.1-0.2-0.1-0.3,0-0.5c0.2-0.2,0.1-0.4,0-0.6c-0.2-0.2-0.3-0.3-0.5-0.2
c-1,0.3-1.8,0.7-2.5,1.2c-0.2,0.2-0.3,0.4-0.3,0.6c0.1,0.3,0.4,0.3,0.6,0.3c0.2-0.1,0.2,0,0.4,0.2c0.1,0.2,0.2,0.3,0.2,0.5
c0,0.1,0.1,0.2,0,0.2c-0.3,0.2-0.4,0.5-0.7,0.7c-0.2,0.2-0.2,0.3,0.1,0.3s0.3,0.3,0.5,0.4c0.1,0.1,0.2,0.2,0,0.2c0,0-0.1,0-0.2,0.1
c-0.5,0.4-1.1,0.7-1.6,1.1c-0.3,0.2-0.7,0.3-0.8,0.8l-0.2,0.2c-0.3,0-0.7,0.3-1,0.4c-0.2,0.1-0.4,0.1-0.2,0.4c0,0,0,0.2-0.2,0.2
l0,0c-0.1,0-0.2,0.1-0.3,0.2c-2,1.1-3.9,2.3-5.8,3.4l0,0c-0.1,0-0.2,0.1-0.3,0.2c-0.8,0.4-1.6,1-2.4,1.4c-0.6,0.4-1.2,0.8-1.7,1
c-0.4,0.2-0.9,0.6-1.3,0.8c-0.8,0.4-1.5,1-2.2,1.4c-0.8,0.4-1.6,1-2.3,1.5c-1,0.6-1.9,1.3-2.9,1.9c-0.5,0.4-1.1,0.7-1.7,1
c-1,0.6-1.8,1.3-2.9,1.8c-0.1,0-0.2,0.1-0.3,0.2l0,0c-0.4,0.2-0.8,0.5-1.2,0.8c-0.1,0-0.2,0.1-0.3,0.2c-0.3,0.2-0.6,0.4-0.9,0.6
c-0.3,0.2-0.6,0.4-0.9,0.6c-0.9,0.6-1.7,1.2-2.6,1.7c-0.5,0.2-0.9,0.6-1.3,0.9c-0.9,0.6-1.6,1.1-2.5,1.7c-0.3,0.2-0.6,0.4-1,0.6
c-0.8,0.5-1.5,1.1-2.4,1.7l0,0c-0.1,0.1-0.3,0.1-0.4,0.3l0,0c-0.5,0.4-1,0.6-1.5,1C0.1,52.8,0,53,0,53.1c0.5,0.2,0.6,0.2,0.7,0.1
c0.4-0.1,0.7-0.3,1.1-0.5l0,0c0.1,0,0.3-0.1,0.4-0.3l0,0c0.6-0.4,1.2-0.7,1.8-1c0.9-0.6,1.8-1.2,2.7-1.9c0.3-0.2,0.7-0.4,1-0.6
c0.8-0.5,1.5-1.1,2.3-1.5c0.6-0.4,1.3-0.8,1.8-1.2c1.1-0.7,2.1-1.4,3.2-2.1c0.9-0.6,1.6-1.1,2.5-1.6c0.8-0.4,1.5-1.1,2.4-1.4l0,0
l0,0c0.1,0,0.2-0.1,0.3-0.2c0.4-0.2,0.8-0.5,1.1-0.7c0.3-0.2,0.7-0.4,1-0.6c0.9-0.6,1.7-1.2,2.6-1.7c0.8-0.4,1.5-1,2.2-1.4
c0.8-0.4,1.6-1,2.4-1.4c0.8-0.4,1.6-1,2.4-1.4c0.7-0.4,1.3-0.9,2.1-1.2l0,0l0,0c0.1,0,0.3-0.1,0.3-0.2c0.7-0.4,1.3-0.7,2-1.1l0,0
l0,0c0.2-0.2,0.4-0.1,0.5-0.4l0,0l0,0c0.8-0.4,1.7-0.9,2.5-1.5c0.3-0.2,0.6-0.4,1-0.5s0.8-0.4,1.1-0.7c0.1-0.1,0.2-0.2,0.3-0.2
c0.3,0,0.6-0.2,0.9-0.2c0.5-0.2,0.9-0.5,1.4-0.7l0,0l0,0c0.1,0.1,0.2-0.1,0.3-0.1c0.4-0.2,0.8-0.3,1.1-0.5c0.1,0,0.2-0.1,0.2,0
c0.2,0.3,0.4,0.5,0.5,0.8c0,0.1,0.2,0.2,0.1,0.4c-0.1,0.1-0.3,0.3-0.4,0.2l0,0l0,0c-0.2-0.2-0.2,0.1-0.3,0.2l0,0l0,0
c0,0.3,0.2,0.4,0.4,0.6c0.5,1.1,1.1,2.2,1.4,3.3c-0.1,0-0.2,0.1-0.3,0.2l0,0c-0.3,0.1-0.6,0-0.9,0.1c-0.1,0-0.3,0-0.4,0.1
c-0.4,0.5-1,0.5-1.5,0.6c-0.5-0.1-0.9-0.1-1.3,0.1c-0.6,0.3-1.2,0.4-1.9,0.7c-0.7,0.3-1.4,0.6-2.1,0.9c-0.5,0.2-1,0.5-1.5,0.6
c-0.7,0.3-1.3,0.6-2,0.9c-0.5,0.2-0.9,0.4-1.4,0.6c-0.9,0.4-1.7,0.8-2.7,1.2c-0.4,0.2-0.8,0.4-1.2,0.6c-0.9,0.4-1.8,0.8-2.8,1.2
c-0.6,0.3-1.1,0.5-1.7,0.8c-0.9,0.4-1.8,0.8-2.7,1.2c-0.7,0.3-1.4,0.7-2.2,1.1c-0.9,0.5-1.7,0.9-2.6,1.3c-0.7,0.3-1.4,0.7-2.2,1.1
c-1.2,0.6-2.4,1.1-3.6,1.8c-1,0.5-2,1.1-3,1.7c-0.1,0-0.3,0.1-0.4,0.2c-0.1,0-0.3,0.2-0.4,0.2c-0.5,0.2-1,0.5-1.3,1
c-0.2,0.3-0.3,0.6-0.4,0.9C6.3,51,6.4,51.7,6.3,52c0.9-0.2,32.6-15.8,33.9-16.5c-0.2,0.1-0.3,0.2-0.5,0.2c0.2-0.1,0.4-0.1,0.5-0.2
c0.1,0,1.3-0.9,2-1.1s1.1-0.4,1.8-0.6c0.5-0.1,0.9-0.5,1.5-0.5c0.3,0,0.5-0.1,0.7-0.3c0.3-0.2,0.6-0.5,0.9-0.5l0,0
c-0.2,0.1-0.2,0.3-0.3,0.4c-0.3,0.3-0.5,0.6-0.9,0.8c-0.6,0.6-1,1.2-1.5,1.8c-0.7,0.9-1.5,1.7-2.2,2.5c-0.1,0.1-0.2,0.3-0.3,0.4
c-0.5,0.4-0.8,0.7-1.3,0.9c-0.6,0.4-1.1,0.7-1.7,1c-0.1,0-0.1,0.1-0.1,0.1c-0.2,0.6-0.1,1.2-0.1,1.7c0,0.1,0,0.3-0.1,0.4
c-0.3,0.3-0.4,0.7-0.7,1c-0.1,0.1-0.4,0.3-0.2,0.5c0.1,0.2,0.1,0.4,0.2,0.5c-0.2,0.2-0.4,0.2-0.6,0.4c-0.8,0.7-1.8,1.3-2.7,2
c-0.2,0.2-0.5,0.2-0.6,0.5c0,0.3-0.1,0.7-0.1,1.2c0,0.8-0.5,1.5-1.3,1.6c0.1-0.1,0.3-0.2,0.1-0.4c-0.2-0.2-0.3,0-0.5,0
s-0.1,0-0.2,0.1c-0.4,0.1-0.9,0.4-1.4,0.5c-0.1,0-0.3,0.1-0.3,0.3c0.1,0.2,0.2,0,0.3,0c0.3-0.1,0.5-0.1,0.8-0.3
c0.1,0,0.2-0.1,0.2,0c0,0.1-0.1,0.1-0.1,0.1c-0.4,0.2-0.8,0.4-1.2,0.6c-1.1,0.5-2.2,1.1-3.2,1.6c-0.5,0.2-1,0.5-1.5,0.6
c-0.6,0.3-1.1,0.4-1.6,1c-0.4,0.6-0.6,1.1-0.7,1.8c0,0.7,0.3,1.4,0.9,1.9c0.2,0.2,0.4,0.2,0.7,0.4c0.6,0.4,1.3,0.5,1.9,0.2
c0.5-0.1,0.9-0.4,1.4-0.6c0.1,0,0.2-0.1,0.3,0c0.2,0.4,0.5,0.2,0.8,0.3c0.1,0,0.1,0,0.1,0.1c0.2,0.3,0.4,0.6,0.5,0.8
c0.6,1,1.9,1.4,3,0.8c0.2-0.1,0.3-0.1,0.4,0.1c0.1,0.5,0.4,1,0.7,1.6c0.3,0.6,0.7,0.9,1.3,0.8c0.6-0.2,1.4-0.5,2-0.6
c0.5-0.1,1-0.4,1.5-0.6c0.3-0.1,0.6,0.1,0.8,0c0.4-0.1,1-0.3,1.4-0.4c0.2-0.1,0.3-0.1,0.4,0.2c0.1,0.2,0.1,0.4,0.3,0.6
c0.1,0.1,0.1,0.2,0,0.2c-0.5,0.2-0.9,0.5-1.4,0.7c-0.1,0-0.2,0.2-0.3,0.3c0,0.2,0,0.5-0.3,0.5c-1,0.2-1.9,0.3-2.8,0.5
c-1,0.3-1.9,0.3-2.8,0.5c-0.7,0.2-1.5,0.2-2.3,0.4c-0.2,0.1-0.4,0.1-0.4,0.2c-0.1,0.5-0.1,0.8-0.1,1.3c0,0.3,0.1,0.5,0.6,0.4
c0.6-0.2,1.3-0.3,1.9-0.5c0.2-0.1,0.3,0,0.6,0c0.6-0.3,1.3-0.3,1.9-0.5c1.1-0.2,2.3-0.5,3.4-0.7c0.2-0.1,0.2,0,0.4,0.1
c0.4,0.6,0.8,0.9,1.6,0.9l0.1,0c0.3,0.3,0.6,0.1,0.9,0c0.3-0.1,0.7-0.2,1,0c0.4,0.2,0.7,0,1.1-0.2c0.2-0.2,0.5-0.4,0.8-0.3
c1,0,2.1-0.1,3.1-0.2c0.1,0.1,0.2-0.1,0.3-0.1l0,0l0,0c0.2-0.2,0.5-0.2,0.7-0.4c0.1,0,0.2-0.1,0.2,0c0.1,0.3,0.3,0.6,0.5,0.9
c0.2,0.4,0.5,0.7,0.9,0.9c0.5,0.3,1,0.4,1.6,0.3c0.5-0.1,1-0.4,1.3-0.9c0.5-0.8,0.5-1.7,0.1-2.5c-0.2-0.5-0.5-1-1-1.5
c0-0.1-0.2-0.2-0.1-0.2c0.3,0,0.6-0.3,0.9-0.4c0.2-0.1,0.3-0.2,0.4-0.3c0.1-0.4,0-0.7-0.2-1.1s-0.7-0.6-1-1.1c0-0.1,0-0.1-0.1-0.1
c-0.6,0-1.1,0-1.7,0c0-0.8,0-0.8,0.6-1.1c0.7-0.3,1.3-0.6,2-1c0.3-0.2,0.6-0.3,0.9-0.5c0.2-0.1,0.3-0.1,0.5,0
c0.2,0,0.5,0.3,0.8,0.4c0.6,0.2,1.1,0.4,1.7,0.6c1.3,0.5,2.5,0.8,3.9,1.2c0.5,0.2,0.9,0.3,1.1,0.8c0.1,0.3,0.3,0.7,0.6,1
c0.6,0.5,1.2,0.9,2,0.7c0.7-0.2,1.4-0.6,1.7-1.4c0.1-0.4,0.1-0.8,0-1.3c0-0.6-0.2-1.1-0.5-1.6c-0.2-0.4-0.6-0.9-1-1.1
c-0.4-0.2-0.7-0.5-1.2-0.5c-0.5,0-0.9,0.1-1.3,0.3l0,0c-0.1,0-0.2,0.1-0.3,0.2l0,0c-0.7,0.4-0.7,1.1-0.8,1.8
c-0.5-0.1-0.9-0.3-1.3-0.5s-0.6-0.4-0.5-0.9c0-0.2-0.1-0.3-0.1-0.4c-0.3-0.3-0.2-0.5-0.3-0.8c0.4,0.5,0.8,0.8,1.1,1.3
c0.2,0.2,0.3,0.3,0.5,0.1c0.1-0.1,0.5-0.2,0.3-0.5c-0.2-0.2-0.2-0.4-0.4-0.6c-0.4-0.5-0.7-1.1-1.1-1.5c0-0.1-0.2-0.2-0.1-0.2
c0.2-0.2,0.4-0.3,0.6-0.2c0.1,0.1,0.2,0,0.3,0c0.6-0.3,1.3-0.3,1.5-1.1c0.1-0.1,0.1-0.1,0.2-0.2c0.6-0.3,1.2-0.6,1.8-0.9
c0.1,0.1,0.3-0.1,0.4-0.1c0.4-0.2,0.7-0.4,1.3-0.3c0.7,0,1.3-0.3,1.6-1l0.1-0.1c0.6-0.2,1.1-0.6,1.7-0.9c0.3-0.2,0.7-0.5,0.9-0.5
c0.3,0.2,0.4,0.6,0.6,0.9c0.1,0.2-0.2,0.5,0.1,0.7c0,0,0,0-0.1,0c-0.2,0.1-0.2,0.2-0.2,0.3c0.1,0.2,0.2,0.2,0.3,0.2
s0.2-0.2,0.4-0.1c-0.1,0.1-0.2,0.2-0.3,0.3c-0.4,0.5-0.3,0.9-0.1,1.4l0,0l0,0c0.1,0.2,0.1,0.3,0.2,0.4l0,0.1
c0.2,0.4,0.6,0.5,1.1,0.5c0.5,0,0.7-0.3,0.8-0.8c0-0.2,0.2-0.2,0.3-0.1c0.5,0.3,1.3-0.1,1.4-0.7c0-0.5-0.1-0.9-0.3-1.3
c-0.5-0.6-1.1-1-1.8-0.2c-0.1,0.1-0.1,0-0.2,0.1c-0.2,0-0.3-0.4-0.6-0.4c-0.2-0.2-0.2-0.3-0.1-0.4s0-0.3-0.1-0.3
c-0.3,0-0.4-0.2-0.5-0.4c-0.2-0.2-0.1-0.4,0.1-0.5c0.6-0.3,1.2-0.7,1.8-1c0.2-0.1,0.4-0.2,0.5-0.2c0.1,0,0.3-0.2,0.1-0.4
c-0.1-0.1-0.2,0-0.3,0c-0.1,0-0.1,0-0.2,0.2c-0.1,0-0.2,0.2-0.3,0.1c-0.1-0.1,0.1-0.1,0-0.2l0-0.1c0.1-0.6,0.2-1.1,0.8-1.1
c0.1,0,0.3-0.3,0.4-0.2c0.3,0.2,0.5,0,0.7-0.1c0.2-0.1,0.1-0.4,0.2-0.4c0.5-0.2,0.5-0.8,1-1.1c0.1,0,0.1-0.1,0-0.2
c-0.1-0.2-0.2-0.4,0.1-0.5c0.2-0.2,0.3-0.3,0.5-0.4c0.1,0,0.5,0.1,0.4-0.3c0-0.1,0.2-0.1,0.2,0c0.2,0.2,0.2,0,0.3,0
c0.7-0.3,1.4-0.7,2.1-1c0.5-0.2,1-0.6,1.6-0.8c0.1,0,0.2-0.3,0.2-0.3c-0.3-0.2-0.2-0.3-0.2-0.5c-0.2-0.2-0.3-0.4-0.4-0.7
c0-0.1,0-0.1,0-0.2c0.1,0,0.3-0.2,0.3,0c0,0.1,0.2,0.2,0.2,0c0.1,0,0.1-0.1,0-0.2c0-0.6,0-0.6,0.5-0.7c0.7-0.2,1.5-0.4,2.2-0.6
c0.4-0.1,0.9-0.2,1.4-0.4c0.1,0,0.2-0.1,0.2,0c0.1,0.3,0.3,0.6,0.3,0.8c0.1,0.2,0.2,0.3,0.3,0.2c0.3-0.2,0.7-0.3,1-0.5
c0.1,0,0.1-0.1,0-0.2c0-0.7,0-1.3-0.1-1.9c-0.1-1.2-0.3-2.4-0.5-3.6c0-0.5-0.1-0.5-0.5-0.3c-0.3,0.1-0.7,0.2-0.7,0.7
c0,0.5-0.1,0.9-0.1,1.5c0,0.8,0,1.7,0,2.5c0,0.1,0.1,0.2,0,0.2c-0.2,0.1-0.3,0.1-0.5,0.1c-0.7,0.1-1.3,0.2-1.9,0.4
c-0.1-0.2,0.2-0.3,0.1-0.4c0.1-0.1,0.2-0.3,0.2-0.3c-0.1-0.3,0.1-0.6,0-0.9c-0.1-0.2,0-0.2,0.3-0.3c0.3-0.1,0.5-0.4,0.3-0.6
c-0.2-0.2-0.1-0.2,0-0.3c0.4-0.8,0.6-1.4,1-2.2c0.7-1.3,1.2-2.7,1.9-4c0.3-0.6,0.7-1.3,0.9-2.1c0.4-0.9,0.8-1.8,1.2-2.6
c0.1-0.1,0.2-0.4,0.1-0.5c-0.1-0.1-0.3,0-0.5,0.1c-0.1,0-0.1,0.1-0.2,0.2c-0.2,0.3-0.2,0.5-0.4,0.8c-0.5,0.8-0.9,1.6-1.4,2.5
c-0.6,1.2-1.3,2.4-2,3.6c-0.3,0.6-0.7,1.2-1,1.9c-0.1,0.4-0.5,0.8-0.6,1.2c0-0.3-0.2-0.4-0.4-0.7c-0.1-0.2-0.1-0.5-0.4-0.6
c-0.1-0.1-0.3-0.2-0.3-0.3c-0.2-0.2-0.3-0.4-0.4-0.7c-0.2-0.2-0.3-0.3-0.5-0.1c-0.7,0.5-1.4,0.8-1.9,1.3c-0.6,0.5-1.3,0.7-2,1.2
c-0.1,0-0.1,0-0.2,0.1c-0.2,0-0.6-0.1-0.8-0.4c-0.4-0.6-1-1-1.5-1.4c-0.7-0.6-1.5-1-2.4-1.3c-0.3-0.2-0.6-0.2-1-0.2
c-0.9-0.2-1.8-0.3-2.6-0.2c-0.9,0.1-1.6,0.9-2.4,1.3c-0.3,0.2-0.6,0.3-0.7,0.7c-0.1,0.1-0.2,0.2-0.3,0.2c-0.3,0-0.7,0-1-0.1
c-0.7,0.1-1.3,0.1-1.9,0.3c-1,0.2-2,0.3-3,0.5c-0.7,0.2-1.6,0.5-2.3,0.6c-1.2,0.1-2.3,0.3-3.5,0.6c-0.1,0-0.2,0.1-0.3,0.2
c0,0.1-0.1,0.1-0.2,0.2s-0.2,0.1-0.4,0.1c-0.3,0.2-0.6,0.2-0.8,0.3c-0.1,0-0.1,0-0.2,0c-0.1-0.2-0.3-0.4-0.3-0.6
c0-0.2,0.3-0.1,0.5-0.1c0.1,0,0.2-0.1,0.2,0c0.2,0,0.3-0.1,0.3-0.2c-0.1-0.2,0.2-0.2,0.3-0.2c0.3-0.1,0.3-0.2,0.2-0.5
c-0.1-0.2-0.3-0.4-0.5-0.4c-0.5-0.4-0.9-0.9-1.5-1.3c0.7-0.5,1.4-0.8,2-1.3c0.2-0.2,0.5-0.2,0.6-0.6l0.1,0c0.5,0,0.9-0.2,1.2-0.4
c0.2-0.1,0.3-0.3,0.4-0.5c2.8-1.5,5.6-3.1,8.4-4.5c0,0,0,0,0.1,0c0.1,0.1,0.3-0.1,0.4-0.1l0,0l0,0c1.9-1,3.8-2,5.8-3l0,0l0,0
c0.1,0.1,0.2-0.1,0.3-0.1c0.4-0.2,0.8-0.4,1.3-0.7c0.1,0.1,0.3-0.1,0.4-0.2c0.9-0.5,1.8-0.9,2.7-1.4c0.8-0.4,1.6-0.8,2.4-1.2
c0.1,0.1,0.3-0.1,0.4-0.1l0,0l0,0c1.7-0.9,3.5-1.7,5.2-2.7l0,0l0,0c0.1,0.1,0.2-0.1,0.4-0.1l0,0l0,0c0.3-0.2,0.6-0.4,0.9-0.5
c1-0.4,2-1,3-1.4c0.6-0.3,1.2-0.6,1.8-0.8c0.9-0.5,1.9-1,2.8-1.3c0.8-0.3,1.6-0.8,2.5-1.2l0,0l0,0c0.1,0.1,0.2-0.1,0.3-0.1l0,0l0,0
c0.2-0.1,0.4-0.2,0.6-0.3l0,0l0,0c0.1,0.1,0.2-0.1,0.3-0.1c1-0.6,2.1-1.1,3.1-1.6C100,6.1,100,6,100,6C100,5.7,100,5.7,99.9,5.6z
M48.7,35.2c0,0.1-0.1,0.1-0.2,0.2c-0.7,0.4-1.4,0.7-2.1,1c-0.1,0-0.1,0.1-0.2,0.2c-0.1,0-0.2,0.2-0.2,0.1c0.7-0.8,1.4-1.5,2.1-2.3
c0.1,0,0.1-0.1,0-0.2s-0.1-0.1-0.2,0c-0.2,0.1-0.3,0-0.5,0c0.2-0.1,0.2-0.4,0.6-0.5c0.1,0,0.2-0.2,0.2,0
C48.4,34.2,48.7,34.6,48.7,35.2z M48.9,34c-0.3-0.4-0.5-0.8-0.2-1.3C48.6,33.3,49.1,33.5,48.9,34z M49.4,32.4
c0.1,0.2,0.1,0.5,0.1,0.8c0,0.1-0.1,0.1-0.2,0.2c-0.1,0-0.1-0.1-0.2-0.2c0-0.1-0.1-0.3-0.2-0.4C48.9,32.6,49.2,32.5,49.4,32.4
C49.3,32.3,49.4,32.3,49.4,32.4z M47,28.7c0.2,0.4,0.4,0.9,0.8,1.3l0,0.1c0,0.2,0.2,0.4,0.4,0.3c0.2-0.1,0.2,0,0.3,0.2
c0.1,0.2-0.1,0.1-0.2,0.2c-0.1,0-0.3,0.2-0.4,0.2c-0.5,0.2-0.5,0.2-0.6-0.3c-0.1-0.5-0.5-1-0.6-1.5c-0.1-0.3-0.3-0.7-0.4-1
c0.2,0,0.4-0.2,0.6-0.2c0.1,0,0.2-0.2,0.2,0c0,0.1,0.2,0.2,0.1,0.3C46.8,28.4,47,28.6,47,28.7z M46.3,26.4
c-0.2,0.1-0.3-0.2-0.3-0.3c-0.2-0.2-0.2-0.4-0.4-0.6c0,0-0.2-0.2-0.1-0.2c0.1-0.1,0.2-0.1,0.2,0C45.9,25.8,46.1,26.1,46.3,26.4z
M47.5,24.9c0.1,0.2,0.1,0.4,0.3,0.6c0,0.1,0,0.1-0.1,0.1c-0.1,0-0.1,0-0.1-0.1s-0.2-0.3-0.2-0.4l0,0c0-0.1-0.1-0.2-0.2-0.3
c0-0.1-0.1-0.2,0-0.2C47.4,24.7,47.4,24.7,47.5,24.9z M50.5,29.7c-0.1,0-0.3,0.1-0.2,0.3c0,0.1,0,0.2-0.2,0.2
c-0.2,0-0.4-0.5-0.2-0.6c0.1-0.1,0.2-0.3,0-0.3c-0.2-0.2-0.2-0.3-0.2-0.5c-0.2-0.4-0.4-0.7-0.6-1.1c-0.1-0.2-0.3-0.3-0.4-0.2
c-0.1,0-0.2,0-0.3-0.2c0-0.1,0-0.2,0.2-0.3c0.2-0.2,0.4-0.2,0.5,0.1c0.1,0.2,0.3,0.4,0.4,0.7c0.4,0.5,0.7,1.1,1.1,1.6
C50.7,29.6,50.7,29.7,50.5,29.7z M52.1,31.8c-0.3-0.2-0.2-0.4-0.3-0.6C52,31.4,52,31.6,52.1,31.8z M53,31.9c-0.5,0-0.5-0.3-0.7-0.6
C52.6,31.4,52.6,31.8,53,31.9z M65.9,21.8c-0.1,0-0.2,0.1-0.3,0.2c-3.1,1.6-6.3,3.3-9.4,5c-0.1,0-0.2,0.2-0.2,0.1
c-0.4-0.1-0.5,0.1-0.8,0.3c-0.2,0.2-0.5,0.2-0.6,0.5l-0.1,0c-0.6-0.1-1,0.4-1.5,0.6c-0.6,0.3-1.1,0.5-1.7,0.8c-0.1,0-0.2,0.1-0.2,0
c-0.3-0.4-0.6-0.9-0.9-1.3c-0.4-0.5-0.6-1.1-1-1.6c-0.1-0.2-0.2-0.3-0.1-0.5s-0.2-0.3-0.3-0.3c-0.3,0.1-0.5-0.1-0.5-0.3
c0-0.1-0.1-0.3-0.2-0.4c-0.2-0.3-0.1-0.3,0.2-0.4s0.5-0.1,0.8-0.3c0.2-0.1,0.5,0.1,0.7,0c0.1,0,0.2,0,0.3-0.1
c0.7-0.4,1.5-0.5,2.2-0.7c0,0.2-0.2,0.3-0.2,0.4c0,0.1-0.2,0.2,0,0.2c0,0.1,0.2,0,0.2,0c0.3-0.1,0.6-0.2,0.9-0.2
c1.3-0.2,2.5-0.5,3.8-0.8c1.3-0.3,2.5-0.4,3.8-0.7c1-0.2,2.1-0.3,3-0.6c1-0.2,2.1-0.3,3.1-0.5c0.1,0,0.3-0.2,0.5,0
C66.7,21.4,66.4,21.7,65.9,21.8z"/>
</g>
<image style="overflow:visible;" width="32" height="32" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAAAmJLR0QA/4ePzL8AAAKFSURBVEjH
nZVdaM1hHMc/z3HYdrY5hNm8v9vWhLzlJYriBldWw4VSpBTJrShJ3LghpLzEBSkhipILJW8lUlpL
S9hwgUVi2M7HxTlnc7a/M87v4v+/eb6/7/f5/l4e+I8w/U3Yj0IiAz/hqQITgHW+94YxM8n+k929
fnJFgdIt97QvjNGLO9Y3POA0WmlkakhJ6OFJH2AB19phXU+AMSuc5fZ4PuYAeJbxVIRPWW4JGGMp
SRp5FR7/nb3MXVZ6wy0AFjvYSsc41Qk2uNmh2UuEvyao5B4prvGLGZST4iMljOUhB3gZvmW1QDxK
OjiQ5bTznYu08Y0PFDMHeBA+d3sRAEujSjbAZe52srPsdAE41x3OdXCEypj1oQdzkulM4H5oAgMX
GEILV8PlrlMl/Ogupgt5ldvnS13nMABne9LbttrhTeP2s9TJVrvbZp84H8C4w90JIcNcxkRqeEor
s1lBLfe5wlHeso7nFDOUZI72tcxjI0do5nSaeZL1Jqz2ug9tcLyY8LW/bDdfrPKO8bgjmclo2jnP
T/aHewCu4gqBQDxPm75BEgTc5jv3WWfZH+42qinzx3AHWAF4vEdpyt3UB/Srx5wSMUyZSmy1KS+8
xUURs2i6++d4Li+40/duyQXHuybsBIsZTSKPbU1sYD3BRHoWchXU5uFtt80nFgN4yMdWRU9fg6t9
FgE/Y7NXrfWwSTBhf6J2UsbAIg+qX2yxI8O90rSxd9X6iI3Vex043xr3+KNLwUQAB/nIJb1sz10o
QjWXeE0by0nynU6KKGFEeJc9mP4LEAupKB+KrLIUrLLGcY5yjbdM5N7WkF62/utT1i02C7OAZwUw
SKEvYoxCmPlH0b8BF043R6DlbZIAAAAASUVORK5CYII=" transform="matrix(1 0 0 1 -36.7427 22.4514)">
</image>
</svg>
<svg enable-background="new 0 0 100 67.1" version="1.0" viewBox="0 0 100 67" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="m68 22c-0.55 0.6-0.25-0.091 0 0z"/>
<path d="m100 5.6c-4.6 1.5-9 4.1-14 6.1-5.1 2.4-10 5.1-15 7.3-3.1-0.24-6.5 0.8-9.7 1.2-4.6 0.59-9 2-13 3.1 2.2-3.1 5.7-4.4 8.2-7.2 5.8-5.5 12-11 18-16-3.4-1.3-7.4 2.2-9.8 4.8-5.9 5.3-12 11-17 16-2.2 1.2-0.53-3.6-3.2-1.2-3.1 0.92 1 2.2-0.84 3.5 1.4 1.3-3.2 2.5-3.5 3.7-7 4.1-14 8.2-21 13-6.4 3.9-13 8.1-19 12 2.1 1.2 6.1-3.3 8.8-4.5 8.1-5.3 16-10 25-15 3.7-1.8 7-4.5 11-5.9 3.2-1.3 0.19 2.1 2.4 3.4 1.5 3.4-4.7 2.1-6.8 3.9-11 4.7-22 9.5-32 15-4 4.7 3.7-0.086 5.9-0.94 8.5-4.1 20-9.6 27-13 1.7-1.2 6.2-2.7 6.6-2.6-2.4 3.1-5.9 5.7-8.1 8.4 0.21 4.1-5 4.4-5.1 8.4-0.48 0.72-2.6-0.39-3.1 1.1 2.9-1-3.4 1.9-4.1 2.3-5.3 0.41-2.3 8.3 1.8 5 1.8 0.38 2.8 3.2 5.1 2.1 0.71 5.5 6.5-1.1 8.4 1.6-2 2.5-6.1 2.2-9.3 3-2.8 1.1 0.19 2.7 2 1.5 3.4-1.9 6.1-0.28 9.3-0.2 3.1-0.39 6.4-2.2 8.4 0.9 4.2 0.45 1.4-4.4 1.6-5.3 2.9-2-2.2-2.6-2.1-3.6 2.9-3 6-1 9.3 0.052 2.3 0.32 4.2 5.1 6.4 1.4 1.5-3.5-4.8-6.6-5.1-2.2-2.2 0.11-2.9-4.4-0.85-1.1 1.6-1.1-3-3.5 0.75-3.5 1.1-1.7 3.4-2.1 5.2-2.5 1.7-2.6 4.2-1.9 4.2-0.25-1.1 0.92 1 4.2 2.2 1.8 2.9 0.21 0.52-3.9-1.2-2.3-3-1.3 2.2-3.3 0.96-3.2-1.1-1.2 2.5-1.6 2.9-3.2 0.32-2 3.9-1.7 5.3-3.4-1.7-2.2 1.8-2.7 4-3.3 2.6 3.7 2.3-6.3 0.24-5.3-1.3 1.2 0.97 4.8-1.3 4.9-3 0.72 0.47-3.5 0.76-5.2 0.82-2.6 4-7 3.3-8.6-1.9 3.3-3.8 6.7-5.6 10-1.2-5-4.4 0.66-6.9-0.2-2.4-3-7.3-4.4-10-1.5-3.5 1.3-8.3 1.5-12 2.5-2 1.5-2.7 0.062-0.65-0.48-2.2-1.8-1.8-2.5 0.65-3.9 3.1-1.5 6.2-3.6 9.5-5.1 5.9-2.7 12-6 18-8.7 5.7-3.1 12-5.4 18-8.5 0.15-0.38 2.1-0.033 1.5-0.9zm-51 30c-1.8 1.2-3.9 2.2-1.1-0.22 0.97-0.65-0.5-2 0.95-0.57zm0.2-1.2c-0.78-1.2-0.0042-1.9 0 0zm0.5-1.6c0.69 2-1.4 0.34 0 0zm-2.4-3.7c1.6 1.2 1.5 3.6 0 1.2-1.5-1.3 0.54-3 0-1.2zm-0.7-2.3c-1.2-0.63-0.83-2.3 0 0zm1.2-1.5c0.93 1.8-1-0.95 0 0zm3 4.8c-0.53 1.1-1.5-2.4-1.9-2.7 0.66-0.18 2 2.2 1.9 2.7zm1.6 2.1c-0.62-0.79-0.21-0.8 0 0zm0.9 0.1c-0.84-0.18-1.1-1.1 0 0zm13-10c-3.7 1.9-7.4 4-11 5.8-2.3 1.6-4.8 2.6-5.7-1.2-2.8-2.1 1.6-2.7 3-2.8 1.5 0.74 6.1-1.3 8.6-1.3 1-0.048 9.3-2.1 5.1-0.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,39 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 43" style="enable-background:new 0 0 100 43;" xml:space="preserve">
<g>
<path d="M45.1,14.9c-0.2-0.2-0.5-0.3-0.7-0.4c-0.5-0.4-0.5-0.7-0.1-1.2c0.6-0.6,1.3-0.9,2-1.3c0.2-0.1,0.4-0.2,0.6-0.3
c-0.4-0.3-0.9-0.2-1.3-0.3c-2.2-0.4-4.4-0.7-6.7-1c-2.1-0.3-4.1-0.6-6.2-0.9c-0.1,0-0.3-0.1-0.4,0c-0.7,0.3-1.4,0-2-0.1
c-1.7-0.2-3.4-0.5-5-0.7c-1.1-0.2-2.2-0.4-3.3-0.5c-0.6-0.1-1.1-0.3-1.7-0.5c-0.5-0.2-1.1-0.2-1.7-0.3c-1.1-0.2-2.2-0.3-3.2-0.5
c-1.4-0.2-2.7-0.4-4.1-0.6C10.5,6,9.7,5.9,8.9,5.8C8.1,5.6,7.2,5.5,6.3,5.3C5.5,5.2,4.8,5.1,4,5C3.8,5,3.6,4.9,3.5,4.8
C3,4.4,2.3,4.5,1.7,4.4C0.8,4.2,0.4,3.9,0.3,3.1c-0.2-0.8,0-1.5,0.5-2.2c0.5-0.6,1.1-0.6,1.7-0.5C3,0.6,3.7,0.8,4.2,0.6
c0.7-0.3,1.4-0.1,2.1,0c1.7,0.3,3.3,0.6,5,0.9c0.4,0.1,0.8,0.2,1.2,0.2c0.3,0,0.6,0,0.7,0.3c0.1,0.2,0.4,0.2,0.5,0.1
c0.3-0.3,0.7-0.1,1.1-0.1c1.9,0.3,3.9,0.7,5.8,1.1c1.2,0.2,2.5,0.4,3.7,0.6C25.2,3.9,26,4,26.8,4.2c1.8,0.3,3.5,0.6,5.3,1
c2.5,0.5,4.9,0.9,7.4,1.3c0.2,0,0.4,0.1,0.6,0.3C40.2,7,40.5,7,40.7,6.9c0.6-0.3,1.1,0,1.7,0.1C44,7.3,45.7,7.6,47.4,8
c0.4,0.1,0.7,0.4,1.1,0.4c1.3,0.1,2.5,0.6,3.9,0.5c0.3,0,0.5-0.1,0.7-0.3c0.2-0.2,0.6-0.3,0.9-0.4c0.1,0,0.2,0,0.2-0.1
c0.9-0.4,0.9-0.4,0.9-1.4c0-0.3,0-0.6,0-1c0-0.3,0.1-0.5,0.5-0.5c0.4,0,0.8,0.1,1.1-0.3c0.1-0.1,0.3-0.1,0.5-0.1
c0.1,0,0.1,0,0.2-0.1c0-0.1,0-0.1-0.1-0.2c-0.3-0.2-0.5-0.2-0.7,0.1c-0.1,0.1-0.2,0.1-0.4,0.2c-0.3,0-0.6-0.1-1,0
c-0.1,0-0.2-0.1-0.2-0.2c0-0.5-0.4-0.5-0.7-0.5c-0.7,0-1.5,0.1-2.2,0.2c-0.3,0.1-0.6,0.1-0.9,0.1c-0.2,0-0.5-0.1-0.4-0.3
c0-0.3,0.3-0.4,0.5-0.4c1.2,0,2.3-0.1,3.4-0.2c0.1,0,0.3,0,0.3-0.2C54.8,3,55,3,55.2,3c0.4,0,0.9,0,1.3,0.1c0.2,0,0.4,0,0.5-0.2
c0.3-0.5,0.8-0.4,1.3-0.4c0.5-0.1,1.1-0.1,1.6-0.1c0.3,0,0.6-0.1,0.8-0.3c0.2-0.1,0.4-0.2,0.6-0.1c0.7,0.1,1.4,0,2.1,0.2
C63.8,2.2,64,2.3,64,2.7c0,0.3,0.2,0.4,0.2,0.7c0.1,0.7-0.4,1.1-0.8,1.5c-0.1,0.1-0.1,0.1-0.1,0.2c0,0.2-0.1,0.3-0.3,0.3
c-0.1,0-0.2,0-0.2,0.2c0,0.1,0.1,0.1,0.2,0.1c0.3,0,0.7-0.1,1-0.1c1-0.1,2-0.2,3-0.3c0.2,0,0.3-0.1,0.3-0.3c0-0.2,0.1-0.3,0.3-0.3
C67.8,4.7,68,4.8,68,5c0,0.3,0.2,0.3,0.4,0.3c1.1-0.1,2.2,0,3.3,0.1c0.8,0,1.5,0,2.3,0.1c1.1,0,2.1,0.2,3.2,0.1
c0.2,0,0.4,0,0.4-0.3c0-0.2,0.2-0.2,0.4-0.3c0.7-0.4,1.6-0.2,2,0.5c0.1,0.2,0.3,0.2,0.5,0.2c0.9,0,1.7,0.1,2.6,0.1
c2.6,0.1,5.2,0.2,7.8,0.3C91.2,6,91.7,6,92.1,6c0.3,0,0.4,0.1,0.5,0.3c0.5,1.7,1,3.4,0.1,5.1c0,0,0,0.1,0,0.1c-0.1,0.6-0.3,1-1,1
c0,0-0.1,0-0.2,0.1c0.5,0,1,0.1,1.4,0.1c1.8,0.2,3.5,0.3,5.3,0.4c0.3,0,0.6,0,0.9,0c0.4,0,0.6,0.2,0.8,0.6c0.5,0.9,0.4,1.8,0.2,2.8
c0,0.1,0,0.3,0,0.4c0,0.2-0.1,0.4-0.2,0.4c-0.3,0-0.3,0.2-0.3,0.5c0.1,0.5,0.1,0.9,0.2,1.4c0,0.5-0.1,1-0.5,1.3
c-0.5,0.4-0.7,1-0.8,1.6c0,1.4-0.7,2.6-1.3,3.7c-0.7,1.3-1.4,2.7-2,4.1c-0.3,0.5-0.7,0.9-1.2,1.1c-0.9,0.4-1.8,0.8-2.8,1.1
c-1.1,0.4-2.1,1-3.2,1.4c-1.2,0.5-2.4,1-3.6,1.5c-1.4,0.6-2.8,1.2-4.2,1.8c-0.8,0.3-1.5,0.7-2.3,1c-1.8,0.8-3.6,1.5-5.5,2.3
c-1.7,0.7-3.3,1.5-5,2.2c-0.9,0.4-1.7,0.5-2.7,0.2c-0.8-0.2-1.6-0.2-2.3-0.4c-0.9-0.2-1.8-0.3-2.6-0.4c-0.8-0.1-1.4-0.5-2-0.9
c-1.4-0.9-2.8-1.8-4.2-2.7c-0.2-0.2-0.5-0.2-0.8-0.2c-0.5,0-1-0.1-1.5-0.2c-0.2,0-0.3,0-0.4,0.2c-0.1,0.4-0.2,0.8-0.3,1.2
c-0.1,0.4-0.3,0.5-0.7,0.4c-0.7-0.2-1.5-0.2-2.2-0.4c-0.7-0.2-1.5-0.4-2.2-0.6c-0.6-0.1-1.2-0.1-1.8-0.2c-0.8-0.1-1.6-0.3-2.4-0.4
c-0.7-0.1-1.5-0.2-2.2-0.3c-0.6,0-1.1-0.2-1.6-0.2c-0.3,0-0.6,0.1-0.9,0.2c-0.9,0.2-1.7,0.2-2.6,0c-0.8-0.1-1.6-0.2-2.4-0.4
c-1.3-0.2-2.5-0.5-3.6-1.2C28,36.1,28,36,27.9,36c-1.3-0.2-2-1.3-3.2-1.8c-1-0.4-1.9-1.1-2.9-1.5c-0.6-0.3-1-0.8-1.2-1.4
c-0.1-0.4-0.4-0.6-0.9-0.6c-0.7-0.1-1.4-0.3-2.1-0.4c-0.2-0.1-0.3-0.2-0.3-0.4c0.1-0.7,0.2-1.5,0.4-2.2c0.1-0.4,0.2-0.8,0.2-1.2
c0-0.6,0.4-1.1,0.7-1.6c0.1-0.1,0.2-0.2,0.2-0.4c0.3-0.7,0.9-1.2,1.5-1.6c0.9-0.6,1.8-1.2,2.8-1.7c0.7-0.3,1.4-0.5,2.1-0.8
c1.4-0.5,2.8-0.9,4.2-1.4c1.2-0.5,2.4-0.9,3.6-1.3c1.1-0.4,2.2-0.7,3.3-0.9c1.6-0.3,3.2-0.6,4.9-0.8c0.2,0,0.4-0.2,0.6-0.3
c0.4-0.4,0.8-0.6,1.4-0.6C43.9,15,44.5,14.9,45.1,14.9z"/>
</g>
</svg>
<svg enable-background="new 0 0 100 43" version="1.0" viewBox="0 0 100 43" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="m45 15c-3.9-1.6 5.3-3.7-0.33-3.6-4.5-0.48-9-1.7-14-1.7-4.2-0.72-8.5-1.2-13-2.2-5.1-0.71-10-1.7-15-2.6-3.6 0.87-4.5-5.3-0.59-4.3 3.4-0.26 6.8 0.75 10 1.3 2.9 0.34 6.6 1.1 9.8 1.6 5.6 0.97 11 2.2 17 3.1 3 0.53 6.5 1.1 9.7 2 2 0.77 6 0.35 5.6-2.5 0.3-1.2 4-1.7 0.64-1.3-0.87-1.4-4.7 0.48-4.8-0.98 3.5 0.03 5.5-1.2 8.9-1.4 2.4-1.7 6.3 1 3 3 0.79 0.58 2.9-0.18 4.1-0.12 2-0.75 6.4 0.57 9.4 0.33 2.4-1.4 4.6 0.64 7.6 0.21 2.8 0.09 5.7 0.28 8.5 0.24 2.1 2-0.53 6.6-0.19 6.6 2.6 1 8.4-1.4 8 3.1-0.33 2.8-1.2 5-2 7.8-1.8 3.3-2.6 8-7 8.5-8.1 3.5-16 7-24 10-3.2-0.19-6.9-0.27-9.7-2.2-1.9-1.1-3.6-2.9-6-2.6-0.42 3.4-4.3 0.65-6.5 0.68-3.7-0.81-7.5-0.85-11-0.88-3.2-0.34-6.1-1.5-8.7-3.3-3-1.1-4.5-3.8-7.4-4.3 0.2-3.5 1.6-7 5.1-8.3 4-1.7 8.2-3 12-4.4 3.6-0.53 7-1.6 10-2.3z"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 911 B

View File

@ -1,51 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 100 79" style="enable-background:new 0 0 100 79;" xml:space="preserve">
<path d="M99.9,64.5c0-0.1,0.1-0.2,0.1-0.2c0-1.2-0.1-2.3-0.1-3.5c0-2.4,0-4.9,0-7.3c0-0.1,0-0.2,0-0.3c0.2-0.3-0.1-0.5-0.2-0.7
c-0.3-0.4-1.1-0.5-0.9-1.3c0-0.1-0.1-0.2-0.1-0.4c-0.1-0.6-0.3-1.3-0.4-1.9c0-0.7,0-1.4,0.1-2c0-0.3,0.1-0.7-0.1-0.8
c-0.2-0.2-0.5-0.1-0.8-0.1c-0.3,0-0.5,0.1-0.7,0.1c-0.5-0.5-1.1-1-1.6-1.5c-0.1-0.1-0.2-0.3-0.2-0.4c0-1.1-0.1-2.1-0.1-3.2
c0-2.2,0-4.4,0-6.5c0-0.7,0-1.4,0-2.1c0-0.3-0.1-0.6-0.3-0.8c-0.7-0.5-1.4-0.8-2.1-1.2c-0.9-0.6-1.9-0.9-3-0.9
c-0.5,0-1.1-0.1-1.7-0.1c-1-0.1-2-0.3-3-0.4c-0.5-0.1-1-0.2-1.5-0.3c0.2-0.1,0.4-0.1,0.5-0.1c0.4,0,0.5-0.2,0.5-0.5c0-0.3,0-0.7,0-1
c0-0.4-0.2-0.5-0.5-0.5c-0.5,0-1,0-1.5,0.1C81.4,26.6,81,27,81,27.8c0,0.1,0,0.1,0,0.2c-0.2,0-0.4-0.1-0.6-0.1
c-0.3-0.1-0.6-0.3-1-0.3c-1.3-0.2-2.6-0.3-3.8-0.5c-0.5-0.1-1-0.1-1.4-0.3c-0.4-0.1-0.8-0.3-1.2-0.4c-0.2-0.1-0.5-0.1-0.5-0.4
c0,0-0.2-0.2-0.4-0.1c-0.4,0-0.9,0.1-1.3,0.1c-0.8-0.1-1.7-0.2-2.5-0.3c0-0.4-0.1-0.7-0.1-1c-0.6-0.1-1-0.2-1.5-0.2c0,0,0-0.1,0-0.1
c0.5,0.1,0.7-0.2,0.8-0.5c0-0.1,0.1-0.2,0.2-0.2c0.2-0.4,0.5-0.5,0.9-0.3c0.2,0.1,0.5,0.1,0.7,0.1c0.9,0,1.7-0.1,2.6-0.2
c0.1,0,0.4-0.1,0.5-0.2c0.2-0.2,0.3-0.4,0.5-0.6c-0.1-0.8-0.1-1.5,0.6-2.1c0.4-0.4,0.6-0.9,0.2-1.5c-0.3-0.4-0.4-0.9-0.6-1.3
c-0.1-0.2-0.1-0.4-0.2-0.7c0-0.4,0.1-0.9-0.4-1.2c0,0-0.1-0.1-0.1-0.1c0-0.4-0.3-0.4-0.6-0.5c-0.1,0-0.3-0.1-0.4-0.1
c-0.7-0.1-1.4-0.5-2.1-0.2c-0.1,0-0.3,0-0.4-0.1c-0.7-0.2-1.3-0.3-2-0.5c-0.3-0.1-0.6-0.3-0.9-0.3c-1-0.2-2-0.5-3-0.4
c-1.3,0.1-2.6,0-4,0c-0.1,0-0.2,0-0.4,0V0c0-0.4-0.2-0.5-0.2,0c0,2.5,0,10.6,0,13.1c0,0.1,0,0.2,0,0.3c0,0.1-0.1,0.1-0.2,0.2
c-0.6,0.2-1.3,0-1.8,0.5c0,0-0.1,0-0.2,0c-0.5-0.1-1-0.2-1.5-0.3c-0.5-0.1-1.1-0.3-1.6-0.4c-0.5-0.1-0.9,0.2-1,0.7
c0,0.3,0.2,0.7,0.6,0.7c0.7,0.1,1.4,0.2,2.1,0.3c0.4,0.1,0.8,0.2,1.4,0.3c-0.2,0.1-0.2,0.1-0.3,0.1c-0.5,0-0.7,0.3-0.8,0.8
c-0.1,0.6-0.2,1.1,0.2,1.6c0.4,0.5,0.8,1.1,1.2,1.7c0.3,0.4,0.6,0.7,0.6,1.2c0,0.3,0.2,0.4,0.5,0.5c0.2,0,0.4,0.1,0.5,0.1v3.9
c-0.2-0.1-0.5-0.1-0.7-0.2c-0.1,0-0.2,0-0.3-0.1c-0.6-0.1-1,0.3-1.5,0.6c-0.4,0.2-0.7,0.7-1.2,0.8c-1.5,0.1-3,0.2-4.5,0.3
c-0.6,0-1.2-0.2-1.7,0.4c0,0-0.1,0-0.2,0c-1.3,0.2-2.6,0.4-3.9,0.6c-1,0.2-2,0.2-2.9-0.1c0.2-0.3,0.3-1.2,0-1.4
c-0.6-0.4-1.1-1-1.9-0.8c-0.3,0.1-0.6,0-0.9,0.1c-0.1,0-0.3,0.1-0.3,0.2c-0.1,0.4-0.1,0.8-0.1,1.2c0,0.2,0.2,0.4,0.3,0.7
c-0.2,0-0.5,0-0.7,0c-0.1,0-0.3,0.1-0.4,0.2c0,0.1,0,0.3,0.1,0.4c0.2,0.3,0.4,0.5,0.6,0.8c0.1,0.1,0.2,0.2,0.1,0.3
c-0.1,0.3-0.2,0.7-0.4,1c-1,1.2-2,2.4-3,3.5c-0.2,0.2-0.4,0.5-0.6,0.7c-0.1-0.3-0.1-0.7-0.6-0.5c0-0.1-0.1-0.1,0-0.2
c0.1-0.5-0.4-0.8-0.5-1.2c0,0-0.1-0.1-0.2-0.1c-0.4,0-0.7,0.3-0.7,0.7c0,0.6,0,1.2,0,1.8c0,0.3-0.1,0.6-0.1,1c-0.4,0-0.7,0-1-0.1
c-0.4-0.2-0.8-0.5-1.1-0.7c-0.4-0.3-0.7-0.3-1.1-0.1c-0.4,0.2-0.6,0.8-0.5,1.2c0.1,0.5,0.2,1,0.4,1.6c-0.5,0-0.9,0-1.4,0
c-1.7,0.1-3.5,0.2-5.2,0.3c-0.9,0.1-1.9,0.1-2.8,0.3c-1.5,0.3-3,0.7-4.5,1.2c-1.1,0.3-2.1,0.6-3.2,1c-1.5,0.5-2.9,1-4.4,1.5
c-0.9,0.3-1.9,0.7-2.8,1.1c-0.8,0.3-1.5,0.6-2.3,0.9c-0.9,0.3-1.2,0.7-1.2,1.7c0,1,0.2,2,0.3,3c0.1,0.6,0.2,1.3,0.2,1.9
c0,0.4,0.2,0.8-0.2,1.1c-0.3,0.2-0.5,0.5-0.1,0.8c0,0,0,0.1,0,0.2c0.1,0.2,0.2,0.5,0.3,0.7c0.1,0.1,0.3,0.2,0.3,0.4
c0,0.4,0.3,0.4,0.6,0.4c0.8,0.1,1.7,0.1,2.5,0.2c0.4,0,0.7,0.1,1.1,0.2c-0.1,0.3-0.2,0.5-0.2,0.7c0,0.3-0.3,0.3-0.5,0.3
c-0.5,0-1-0.1-1.4-0.1c-1.1,0-2.2,0-3.3,0c-0.3,0-0.4,0.1-0.5,0.4c0,0.1,0,0.2,0,0.4c0,1.1-0.1,2.1,0,3.2c0,0.2,0.2,0.4,0.3,0.5
c0.2,0.1,0.4,0.1,0.6,0.1c1.3,0.2,2.5,0.4,3.7,0.6c0.2,0.3,0.4,0.6,0.6,0.9c0,0.1,0.1,0.1,0.1,0.2c0,0.3-0.1,0.7-0.2,1
c-0.2,0.6-0.5,1.3-0.8,1.9c-0.2,0.5,0.1,1,0.6,1c0.3,0,0.4,0.2,0.4,0.5c0.1,0.6,0.1,1.1,0.3,1.7c0.1,0.3,0.2,0.5,0.3,0.8
c0.4,1.1,0.6,2.2,1.5,3c0.7,0.7,1.2,1.6,2.1,2.1c1.1,0.7,2.3,1.3,3.6,1.5c1.3,0.2,2.7,0.2,4,0.4c0.4,0,0.9,0.1,1.3,0.1
c0.8-0.2,1.7-0.4,2.5-0.7c0.5-0.2,0.9-0.5,1.3-0.8c0.7-0.5,1.5-0.9,2-1.7c0.7-1.1,1.7-2.1,2.1-3.4c0-0.1,0.2-0.2,0.3-0.2
c0.6,0,1.1,0.1,1.7,0.1c0.8,0,1.6,0,2.5,0c0.8,0,1.5-0.1,2.3,0c0.9,0.1,1.8,0.3,2.7,0.6c0.2,0,0.4,0.2,0.4,0.4
c0,0.8,0.3,1.4,0.5,2.1c0.4,1.2,0.7,2.4,1.5,3.4c0.5,0.5,0.7,1.3,1.3,1.7c1.1,0.8,2.2,1.7,3.7,2c1.1,0.2,2.1,0.5,3.2,0.4
c0.2,0,0.5,0,0.8,0c1,0.2,2,0.1,3-0.1c0.4-0.1,0.9-0.1,1.3-0.3c0.5-0.1,1.2-0.1,1.6-0.5c0.5-0.5,1-1,1.6-1.5
c0.5-0.4,0.8-0.8,1.1-1.3c0.1-0.2,0.3-0.4,0.4-0.7c0.3-0.6,0.7-1.2,1-1.8c0.3-0.6,0.5-1.3,0.7-2c0.3-0.8,0.5-1.6,0.7-2.4
c0.4,0.1,0.8,0.2,1.3,0.3c0.6,0.1,1.2,0.2,1.8,0.3c1,0,1.9,0,2.9,0c0.1,0,0.2,0,0.3,0c1.3-0.4,2.2-1.3,3-2.3c0.4-0.6,0.8-1.3,1.1-2
c0.3-0.8,0.6-1.2,1.5-1.1c0.9,0,1.7-0.1,2.6-0.1c1.2,0,2.4,0.1,3.5,0.2c0.7,0,1.4-0.1,2.1-0.1c1.4,0.2,2.8,0.5,4.2,0.7
c0.3,0,0.3,0.2,0.3,0.4c0,0.3,0.1,0.7,0.2,1c0.1,0.3,0.2,0.6,0.3,1c0.5,1.6,1.1,3,2.5,3.9c0.3,0.2,0.5,0.5,0.8,0.5
c1.1,0.2,2.3,0.3,3.4,0.3c1,0,2-0.1,2.9-0.2c0.7-0.1,1.3-0.3,1.7-0.9c1.2-1.5,2-3.2,2.4-5.1c0.1-0.3,0.2-0.4,0.5-0.4
c0.4,0,0.9,0.1,1.3,0.1c0.3,0,0.6,0,0.8-0.1C100,65.1,99.9,64.8,99.9,64.5z M38.7,34.7c1.2-0.5,2.4-1,3.7-1.6c0,0.3,0.1,0.5,0.1,0.8
C40.8,34.9,40.7,34.7,38.7,34.7z M42.5,32.7c-0.8,0.3-1.6,0.6-2.4,0.9c-0.4,0.1-0.8,0.3-1.3,0.4c-0.1,0-0.2,0-0.4,0
c0.7-0.7,1.2-1.3,1.8-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.6,0.1,1.2,0.1,1.8,0.2C42.9,32.4,42.8,32.6,42.5,32.7z M52.6,34.2
c-0.2,0-0.5,0-0.7,0c-0.1-0.3-0.1-0.6-0.2-0.9c0.3,0.3,0.6,0.5,0.9,0.7C52.6,34.2,52.6,34.2,52.6,34.2z M53.8,33.5
c-0.1,0.3-0.1,0.5-0.1,0.7h-0.7c0,0,0,0,0,0c0,0,0,0,0,0c0.1-0.1,0.1-0.1,0.2-0.2l-0.9-0.4c0,0,0,0,0,0c0,0,0,0-0.1,0
c0,0,0.1-0.1,0.1-0.1C52.8,33.4,53.3,33.4,53.8,33.5C53.8,33.5,53.8,33.5,53.8,33.5L53.8,33.5z"/>
</svg>
<svg enable-background="new 0 0 100 79" version="1.0" viewBox="0 0 100 79" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="m100 64c0.053-3.8-0.045-7.8 0.012-12-3-2 0.34-7.4-3.9-7.5-2-1.8-0.78-5-1.1-7.4-0.18-2.1 0.36-4.3-0.3-6.3-3.1-2.7-7.3-2-11-2.9 2.2-0.62-0.63-3.8-2.5-1.5-2.2 1.6-7.2-1.4-10-1.3-1.9 0.45-3.5-1.7-3.8-1.6 1.9-2 6.4 0.24 6.5-4 0.72-2.7-1.1-6.6-4.6-5.7-3.1-1.7-8-0.42-10-1.7-0.067-4.4 0.13-8.9-0.1-13-0.23 4.6-0.034 9.2-0.1 14-1.4 2.1-6.7-1.7-6 1.3 2.2 0.61 4.5-0.2 2.6 2.4 0.79 2.7 3.7 3.7 3.1 6.6 0.67 2.6-2.9 0.96-4.2 2.7-2.3 0.2-4.6 0.12-6.6 0.78-1.9-0.021-6.1 1.9-5.9-0.76-1.2-2.2-4.4-0.72-3.3 1.1-1.4 0.24 1.1 3.1-1.6 4-1.5 1.9-2.9 3.8-3.8 0.86-1.5 0.92 0.17 5.3-2.9 2.7-3-0.82 0.15 3.9-3.2 2.7-5.6-0.037-11 1.2-16 3.1-3 1.8-9.3 1.4-9.6 5.6 1.5 2.6-1.6 7.1 2 7.8 3.3-0.55 3.5 2.1 0.11 1.2-3.1-0.88-3.8 1.6-2.9 4.3 3.9-8.5e-4 6.6 1.7 4.2 5.6 2 3.3 3.2 9.5 8.8 9.9 4.9 1.4 11-0.21 13-5.2 1.4-2.1 5.4-0.56 7.9-0.93 4.4 0.26 2.5 7.1 6.6 8.7 3 2.2 7 2 11 1.6 3.8-0.56 6-4.6 7-8-0.065-3.6 2.8-1.5 5.1-1.8 3.3 0.64 5.4-2.6 6.5-5.2 3.8-0.52 7.9-0.34 12 0.23 3.7 0.11 1.9 7.2 6.5 7.2 4.8 1.5 9.2-1.3 9.7-6.3 1-0.39 3.2 0.9 2.4-1.3zm-61-30c1.9-1.6 5.8-1.5 2-0.025-0.67 0.081-1.3 0.014-2 0.025zm3.8-2c-1.9 0.79-6 2.3-2.3-0.5 0.32-0.54 3.6-0.35 2.3 0.5zm10 1.5c-1.5 0.22-0.68-1.7 0 0zm1.2-0.7c0.47 1.9-3.5-1 0 0z"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB