├── website ├── js │ ├── _util.js │ ├── game.js │ ├── server.js │ ├── players.js │ └── main.js ├── views │ ├── empty.pug │ ├── _partials │ │ ├── clans-online.pug │ │ ├── similar-games.pug │ │ └── player-search-results.pug │ ├── stats.pug │ ├── profile.pug │ ├── game.pug │ ├── error.pug │ ├── metrics.pug │ └── server.pug └── styles │ └── _nprogress.scss ├── assets ├── images │ ├── 6.jpg │ ├── squid.png │ ├── flags │ │ ├── AD.png │ │ ├── AE.png │ │ ├── AF.png │ │ ├── AG.png │ │ ├── AI.png │ │ ├── AL.png │ │ ├── AM.png │ │ ├── AN.png │ │ ├── AO.png │ │ ├── AQ.png │ │ ├── AR.png │ │ ├── AS.png │ │ ├── AT.png │ │ ├── AU.png │ │ ├── AW.png │ │ ├── AZ.png │ │ ├── BA.png │ │ ├── BB.png │ │ ├── BD.png │ │ ├── BE.png │ │ ├── BF.png │ │ ├── BG.png │ │ ├── BH.png │ │ ├── BI.png │ │ ├── BJ.png │ │ ├── BM.png │ │ ├── BN.png │ │ ├── BO.png │ │ ├── BR.png │ │ ├── BS.png │ │ ├── BT.png │ │ ├── BW.png │ │ ├── BY.png │ │ ├── BZ.png │ │ ├── CA.png │ │ ├── CD.png │ │ ├── CF.png │ │ ├── CG.png │ │ ├── CH.png │ │ ├── CI.png │ │ ├── CK.png │ │ ├── CL.png │ │ ├── CM.png │ │ ├── CN.png │ │ ├── CO.png │ │ ├── CR.png │ │ ├── CU.png │ │ ├── CV.png │ │ ├── CY.png │ │ ├── CZ.png │ │ ├── DE.png │ │ ├── DJ.png │ │ ├── DK.png │ │ ├── DM.png │ │ ├── DO.png │ │ ├── DZ.png │ │ ├── EC.png │ │ ├── EE.png │ │ ├── EG.png │ │ ├── EH.png │ │ ├── ER.png │ │ ├── ES.png │ │ ├── ET.png │ │ ├── EU.png │ │ ├── FI.png │ │ ├── FJ.png │ │ ├── FM.png │ │ ├── FO.png │ │ ├── FR.png │ │ ├── GA.png │ │ ├── GB.png │ │ ├── GD.png │ │ ├── GE.png │ │ ├── GG.png │ │ ├── GH.png │ │ ├── GI.png │ │ ├── GL.png │ │ ├── GM.png │ │ ├── GN.png │ │ ├── GP.png │ │ ├── GQ.png │ │ ├── GR.png │ │ ├── GT.png │ │ ├── GU.png │ │ ├── GW.png │ │ ├── GY.png │ │ ├── HK.png │ │ ├── HN.png │ │ ├── HR.png │ │ ├── HT.png │ │ ├── HU.png │ │ ├── ID.png │ │ ├── IE.png │ │ ├── IL.png │ │ ├── IM.png │ │ ├── IN.png │ │ ├── IQ.png │ │ ├── IR.png │ │ ├── IS.png │ │ ├── IT.png │ │ ├── JE.png │ │ ├── JM.png │ │ ├── JO.png │ │ ├── JP.png │ │ ├── KE.png │ │ ├── KG.png │ │ ├── KH.png │ │ ├── KI.png │ │ ├── KM.png │ │ ├── KN.png │ │ ├── KP.png │ │ ├── KR.png │ │ ├── KW.png │ │ ├── KY.png │ │ ├── KZ.png │ │ ├── LA.png │ │ ├── LB.png │ │ ├── LC.png │ │ ├── LI.png │ │ ├── LK.png │ │ ├── LR.png │ │ ├── LS.png │ │ ├── LT.png │ │ ├── LU.png │ │ ├── LV.png │ │ ├── LY.png │ │ ├── MA.png │ │ ├── MC.png │ │ ├── MD.png │ │ ├── ME.png │ │ ├── MG.png │ │ ├── MH.png │ │ ├── MK.png │ │ ├── ML.png │ │ ├── MM.png │ │ ├── MN.png │ │ ├── MO.png │ │ ├── MQ.png │ │ ├── MR.png │ │ ├── MS.png │ │ ├── MT.png │ │ ├── MU.png │ │ ├── MV.png │ │ ├── MW.png │ │ ├── MX.png │ │ ├── MY.png │ │ ├── MZ.png │ │ ├── NA.png │ │ ├── NC.png │ │ ├── NE.png │ │ ├── NG.png │ │ ├── NI.png │ │ ├── NL.png │ │ ├── NO.png │ │ ├── NP.png │ │ ├── NR.png │ │ ├── NZ.png │ │ ├── OM.png │ │ ├── PA.png │ │ ├── PE.png │ │ ├── PF.png │ │ ├── PG.png │ │ ├── PH.png │ │ ├── PK.png │ │ ├── PL.png │ │ ├── PR.png │ │ ├── PS.png │ │ ├── PT.png │ │ ├── PW.png │ │ ├── PY.png │ │ ├── QA.png │ │ ├── RE.png │ │ ├── RO.png │ │ ├── RS.png │ │ ├── RU.png │ │ ├── RW.png │ │ ├── SA.png │ │ ├── SB.png │ │ ├── SC.png │ │ ├── SD.png │ │ ├── SE.png │ │ ├── SG.png │ │ ├── SI.png │ │ ├── SK.png │ │ ├── SL.png │ │ ├── SM.png │ │ ├── SN.png │ │ ├── SO.png │ │ ├── SR.png │ │ ├── ST.png │ │ ├── SV.png │ │ ├── SY.png │ │ ├── SZ.png │ │ ├── TC.png │ │ ├── TD.png │ │ ├── TG.png │ │ ├── TH.png │ │ ├── TJ.png │ │ ├── TL.png │ │ ├── TM.png │ │ ├── TN.png │ │ ├── TO.png │ │ ├── TR.png │ │ ├── TT.png │ │ ├── TV.png │ │ ├── TW.png │ │ ├── TZ.png │ │ ├── UA.png │ │ ├── UG.png │ │ ├── US.png │ │ ├── UY.png │ │ ├── UZ.png │ │ ├── VA.png │ │ ├── VC.png │ │ ├── VE.png │ │ ├── VG.png │ │ ├── VI.png │ │ ├── VN.png │ │ ├── VU.png │ │ ├── WS.png │ │ ├── YE.png │ │ ├── ZA.png │ │ ├── ZM.png │ │ └── ZW.png │ ├── icons │ │ ├── mp5.png │ │ ├── flag.png │ │ ├── skull.png │ │ ├── backstab.png │ │ ├── crosshair.png │ │ └── LICENSE │ ├── mapshots │ │ ├── ot.jpg │ │ ├── ow.jpg │ │ ├── ra.jpg │ │ ├── abbey.jpg │ │ ├── abyss.jpg │ │ ├── alloy.jpg │ │ ├── antel.jpg │ │ ├── aod.jpg │ │ ├── bklyn.jpg │ │ ├── campo.jpg │ │ ├── casa.jpg │ │ ├── clash.jpg │ │ ├── croma.jpg │ │ ├── depot.jpg │ │ ├── disc.jpg │ │ ├── dock.jpg │ │ ├── donya.jpg │ │ ├── douze.jpg │ │ ├── duel5.jpg │ │ ├── duel7.jpg │ │ ├── duel8.jpg │ │ ├── dune.jpg │ │ ├── duomo.jpg │ │ ├── dust2.jpg │ │ ├── dust4.jpg │ │ ├── dust6.jpg │ │ ├── elegy.jpg │ │ ├── eris.jpg │ │ ├── exist.jpg │ │ ├── exo.jpg │ │ ├── fc3.jpg │ │ ├── fc4.jpg │ │ ├── fc5.jpg │ │ ├── fdm6.jpg │ │ ├── force.jpg │ │ ├── forge.jpg │ │ ├── frag2.jpg │ │ ├── fury.jpg │ │ ├── gorge.jpg │ │ ├── gubo.jpg │ │ ├── hades.jpg │ │ ├── hallo.jpg │ │ ├── hashi.jpg │ │ ├── haste.jpg │ │ ├── hator.jpg │ │ ├── haze.jpg │ │ ├── hdm3.jpg │ │ ├── hog2.jpg │ │ ├── horus.jpg │ │ ├── idris.jpg │ │ ├── kffa.jpg │ │ ├── kiryu.jpg │ │ ├── kmap5.jpg │ │ ├── ks2.jpg │ │ ├── l_ctf.jpg │ │ ├── lost.jpg │ │ ├── luna.jpg │ │ ├── mach2.jpg │ │ ├── maple.jpg │ │ ├── masdm.jpg │ │ ├── mbt1.jpg │ │ ├── mbt10.jpg │ │ ├── mbt12.jpg │ │ ├── mbt2.jpg │ │ ├── mbt4.jpg │ │ ├── mbt9.jpg │ │ ├── metl2.jpg │ │ ├── metl3.jpg │ │ ├── metl4.jpg │ │ ├── mill.jpg │ │ ├── nitro.jpg │ │ ├── nmp4.jpg │ │ ├── nmp8.jpg │ │ ├── nmp9.jpg │ │ ├── oasis.jpg │ │ ├── orbe.jpg │ │ ├── orion.jpg │ │ ├── park.jpg │ │ ├── pgdm.jpg │ │ ├── regal.jpg │ │ ├── relic.jpg │ │ ├── risk.jpg │ │ ├── rkc2.jpg │ │ ├── rm1.jpg │ │ ├── rm5.jpg │ │ ├── ruby.jpg │ │ ├── ruine.jpg │ │ ├── rust.jpg │ │ ├── sdm1.jpg │ │ ├── shiva.jpg │ │ ├── siege.jpg │ │ ├── souls.jpg │ │ ├── spcr.jpg │ │ ├── spcr2.jpg │ │ ├── star.jpg │ │ ├── surge.jpg │ │ ├── tejen.jpg │ │ ├── thor.jpg │ │ ├── tubes.jpg │ │ ├── wake5.jpg │ │ ├── waltz.jpg │ │ ├── wdcd.jpg │ │ ├── xenon.jpg │ │ ├── zdm2.jpg │ │ ├── ztn.jpg │ │ ├── DM_BS1.jpg │ │ ├── aard3c.jpg │ │ ├── academy.jpg │ │ ├── access.jpg │ │ ├── alithia.jpg │ │ ├── anubis.jpg │ │ ├── arabic.jpg │ │ ├── arbana.jpg │ │ ├── asgard.jpg │ │ ├── asthma.jpg │ │ ├── autumn.jpg │ │ ├── averas.jpg │ │ ├── awoken.jpg │ │ ├── bvdm_01.jpg │ │ ├── c_egypt.jpg │ │ ├── canyon.jpg │ │ ├── carbide.jpg │ │ ├── cartel.jpg │ │ ├── catch22.jpg │ │ ├── collide.jpg │ │ ├── colony.jpg │ │ ├── complex.jpg │ │ ├── crnsp1.jpg │ │ ├── crust1.jpg │ │ ├── crust2.jpg │ │ ├── crypta.jpg │ │ ├── curvedm.jpg │ │ ├── daemex.jpg │ │ ├── destiny.jpg │ │ ├── dispute.jpg │ │ ├── enigma.jpg │ │ ├── fallen.jpg │ │ ├── frozen.jpg │ │ ├── fubuki.jpg │ │ ├── fusion.jpg │ │ ├── garden.jpg │ │ ├── genesis.jpg │ │ ├── ghetto.jpg │ │ ├── hektik.jpg │ │ ├── hidden.jpg │ │ ├── idyll3.jpg │ │ ├── infamy.jpg │ │ ├── insipid.jpg │ │ ├── island.jpg │ │ ├── janela.jpg │ │ ├── justice.jpg │ │ ├── k_rpg1.jpg │ │ ├── kastro.jpg │ │ ├── ksauer1.jpg │ │ ├── ladder.jpg │ │ ├── laucin.jpg │ │ ├── legacy.jpg │ │ ├── legazzo.jpg │ │ ├── level9.jpg │ │ ├── mc-lab.jpg │ │ ├── memento.jpg │ │ ├── memoria.jpg │ │ ├── mercury.jpg │ │ ├── mpsp10.jpg │ │ ├── mpsp6a.jpg │ │ ├── mpsp6b.jpg │ │ ├── mpsp6c.jpg │ │ ├── mpsp9a.jpg │ │ ├── mpsp9b.jpg │ │ ├── mpsp9c.jpg │ │ ├── nessus.jpg │ │ ├── nevil_c.jpg │ │ ├── nucleus.jpg │ │ ├── ognjen.jpg │ │ ├── osiris.jpg │ │ ├── outpost.jpg │ │ ├── pandora.jpg │ │ ├── pariah.jpg │ │ ├── pul1ctf.jpg │ │ ├── refuge.jpg │ │ ├── reissen.jpg │ │ ├── river_c.jpg │ │ ├── rpg_01.jpg │ │ ├── ruebli.jpg │ │ ├── saffier.jpg │ │ ├── shindou.jpg │ │ ├── siberia.jpg │ │ ├── skrdm1.jpg │ │ ├── skrsp1.jpg │ │ ├── spiralz.jpg │ │ ├── stadium.jpg │ │ ├── stemple.jpg │ │ ├── stolen.jpg │ │ ├── suburb.jpg │ │ ├── suisei.jpg │ │ ├── tartech.jpg │ │ ├── tempest.jpg │ │ ├── torment.jpg │ │ ├── tortuga.jpg │ │ ├── tumwalk.jpg │ │ ├── turbine.jpg │ │ ├── turmoil.jpg │ │ ├── unworld.jpg │ │ ├── urban_c.jpg │ │ ├── venice.jpg │ │ ├── warlock.jpg │ │ ├── zavial.jpg │ │ ├── akaritori.jpg │ │ ├── akimiski.jpg │ │ ├── akroseum.jpg │ │ ├── albatross.jpg │ │ ├── aqueducts.jpg │ │ ├── asenatra.jpg │ │ ├── asteroids.jpg │ │ ├── authentic.jpg │ │ ├── bad_moon.jpg │ │ ├── box_demo.jpg │ │ ├── breakout.jpg │ │ ├── bt_falls.jpg │ │ ├── c_valley.jpg │ │ ├── caribbean.jpg │ │ ├── collusion.jpg │ │ ├── conflict.jpg │ │ ├── corruption.jpg │ │ ├── ctf_suite.jpg │ │ ├── cwcastle.jpg │ │ ├── damnation.jpg │ │ ├── darkdeath.jpg │ │ ├── deathtek.jpg │ │ ├── dirtndust.jpg │ │ ├── disruption.jpg │ │ ├── door_demo.jpg │ │ ├── dopamine.jpg │ │ ├── earthsea.jpg │ │ ├── europium.jpg │ │ ├── evilness.jpg │ │ ├── ex_example.jpg │ │ ├── fb_capture.jpg │ │ ├── ferguson.jpg │ │ ├── fire_keep.jpg │ │ ├── flagstone.jpg │ │ ├── forgotten.jpg │ │ ├── fortress.jpg │ │ ├── frag-lab.jpg │ │ ├── fragnostic.jpg │ │ ├── fragplaza.jpg │ │ ├── frostbyte.jpg │ │ ├── frozen6a.jpg │ │ ├── gothic-df.jpg │ │ ├── guacamole.jpg │ │ ├── gunmetal.jpg │ │ ├── headroom.jpg │ │ ├── helligsted.jpg │ │ ├── hillfort.jpg │ │ ├── industry.jpg │ │ ├── infernal.jpg │ │ ├── injustice.jpg │ │ ├── kalking1.jpg │ │ ├── katrez_d.jpg │ │ ├── killcore3.jpg │ │ ├── konkuri-to.jpg │ │ ├── kopenhagen.jpg │ │ ├── lost_soul.jpg │ │ ├── lost_world.jpg │ │ ├── meltdown2.jpg │ │ ├── memento2b.jpg │ │ ├── monastery.jpg │ │ ├── moonlite.jpg │ │ ├── neonpanic.jpg │ │ ├── nevil_c2.jpg │ │ ├── new_energy.jpg │ │ ├── oddworld.jpg │ │ ├── ogrosupply.jpg │ │ ├── oldschool.jpg │ │ ├── overdrive.jpg │ │ ├── paradigm.jpg │ │ ├── ph-capture.jpg │ │ ├── phosgene.jpg │ │ ├── phrantic.jpg │ │ ├── powerplant.jpg │ │ ├── purgatory.jpg │ │ ├── recovery.jpg │ │ ├── redemption.jpg │ │ ├── renegade.jpg │ │ ├── river_keep.jpg │ │ ├── roughinery.jpg │ │ ├── sacrifice.jpg │ │ ├── sandstorm.jpg │ │ ├── sandstorm2.jpg │ │ ├── sauerowalk.jpg │ │ ├── serenity.jpg │ │ ├── shadowed.jpg │ │ ├── shinmei1.jpg │ │ ├── shipwreck.jpg │ │ ├── simplicity.jpg │ │ ├── stahlbox.jpg │ │ ├── stronghold.jpg │ │ ├── subterra.jpg │ │ ├── tatooine.jpg │ │ ├── teahupoo.jpg │ │ ├── tectonic.jpg │ │ ├── thetowers.jpg │ │ ├── toxicity.jpg │ │ ├── triforts.jpg │ │ ├── turbulence.jpg │ │ ├── twinforts.jpg │ │ ├── unworld2.jpg │ │ ├── unworld3.jpg │ │ ├── valhalla.jpg │ │ ├── ventania.jpg │ │ ├── berlin_wall.jpg │ │ ├── castle_trap.jpg │ │ ├── core_refuge.jpg │ │ ├── curvy_castle.jpg │ │ ├── desecration.jpg │ │ ├── earthstation.jpg │ │ ├── face-capture.jpg │ │ ├── firstevermap.jpg │ │ ├── killfactory.jpg │ │ ├── lostinspace.jpg │ │ ├── pitch_black.jpg │ │ ├── sauerbraten.jpg │ │ ├── sauerstruck.jpg │ │ ├── shellshock2.jpg │ │ ├── capture_night.jpg │ │ ├── core_transfer.jpg │ │ ├── eternal_valley.jpg │ │ ├── fanatic_quake.jpg │ │ ├── hiddenfortress.jpg │ │ ├── neondevastation.jpg │ │ ├── platform_demo.jpg │ │ ├── secondevermap.jpg │ │ └── snapper_rocks.jpg │ ├── 213425634sad.png │ └── convert.sh └── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── .babelrc ├── IP2LOCATION-LITE-DB1.BIN ├── .prettierrc ├── docker-entrypoint.sh ├── src ├── api │ ├── v2 │ │ ├── main.js │ │ ├── servers.js │ │ ├── server.js │ │ ├── clans.js │ │ └── players.js │ ├── v1 │ │ ├── main.js │ │ ├── servers.js │ │ └── clan.js │ └── team-balance.js ├── util │ ├── database.js │ ├── redis.js │ ├── country.js │ ├── config.js │ ├── protocol.js │ ├── metrics.js │ ├── web.js │ └── cache.js ├── web │ ├── banners.js │ ├── metrics.js │ ├── index.js │ ├── servers.js │ ├── clan.js │ ├── game.js │ ├── server.js │ ├── stats.js │ └── player.js ├── index.js ├── tracker │ ├── spy.js │ ├── master.js │ └── player-manager.js └── scripts │ ├── detect-clanwars.js │ └── recalculate-elo.js ├── .gitignore ├── knexfile.js ├── .dockerignore ├── Dockerfile ├── migrations ├── 20160510143720_remove_server_keep.js ├── 20171007201942_unique_players_name.js ├── 20180215000343_delete_requests_table.js ├── 20180214035158_update_players_schema.js ├── 20171211131355_add_constraints.js ├── 20180214041134_update_players_schema_2.js └── 20161202143509_update_mode_names.js ├── docker-compose.yml ├── webpack.config.js └── package.json /website/js/_util.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/6.jpg -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-node" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /IP2LOCATION-LITE-DB1.BIN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/IP2LOCATION-LITE-DB1.BIN -------------------------------------------------------------------------------- /assets/images/squid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/squid.png -------------------------------------------------------------------------------- /assets/images/flags/AD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AD.png -------------------------------------------------------------------------------- /assets/images/flags/AE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AE.png -------------------------------------------------------------------------------- /assets/images/flags/AF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AF.png -------------------------------------------------------------------------------- /assets/images/flags/AG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AG.png -------------------------------------------------------------------------------- /assets/images/flags/AI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AI.png -------------------------------------------------------------------------------- /assets/images/flags/AL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AL.png -------------------------------------------------------------------------------- /assets/images/flags/AM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AM.png -------------------------------------------------------------------------------- /assets/images/flags/AN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AN.png -------------------------------------------------------------------------------- /assets/images/flags/AO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AO.png -------------------------------------------------------------------------------- /assets/images/flags/AQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AQ.png -------------------------------------------------------------------------------- /assets/images/flags/AR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AR.png -------------------------------------------------------------------------------- /assets/images/flags/AS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AS.png -------------------------------------------------------------------------------- /assets/images/flags/AT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AT.png -------------------------------------------------------------------------------- /assets/images/flags/AU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AU.png -------------------------------------------------------------------------------- /assets/images/flags/AW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AW.png -------------------------------------------------------------------------------- /assets/images/flags/AZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/AZ.png -------------------------------------------------------------------------------- /assets/images/flags/BA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BA.png -------------------------------------------------------------------------------- /assets/images/flags/BB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BB.png -------------------------------------------------------------------------------- /assets/images/flags/BD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BD.png -------------------------------------------------------------------------------- /assets/images/flags/BE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BE.png -------------------------------------------------------------------------------- /assets/images/flags/BF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BF.png -------------------------------------------------------------------------------- /assets/images/flags/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BG.png -------------------------------------------------------------------------------- /assets/images/flags/BH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BH.png -------------------------------------------------------------------------------- /assets/images/flags/BI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BI.png -------------------------------------------------------------------------------- /assets/images/flags/BJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BJ.png -------------------------------------------------------------------------------- /assets/images/flags/BM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BM.png -------------------------------------------------------------------------------- /assets/images/flags/BN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BN.png -------------------------------------------------------------------------------- /assets/images/flags/BO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BO.png -------------------------------------------------------------------------------- /assets/images/flags/BR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BR.png -------------------------------------------------------------------------------- /assets/images/flags/BS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BS.png -------------------------------------------------------------------------------- /assets/images/flags/BT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BT.png -------------------------------------------------------------------------------- /assets/images/flags/BW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BW.png -------------------------------------------------------------------------------- /assets/images/flags/BY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BY.png -------------------------------------------------------------------------------- /assets/images/flags/BZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/BZ.png -------------------------------------------------------------------------------- /assets/images/flags/CA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CA.png -------------------------------------------------------------------------------- /assets/images/flags/CD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CD.png -------------------------------------------------------------------------------- /assets/images/flags/CF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CF.png -------------------------------------------------------------------------------- /assets/images/flags/CG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CG.png -------------------------------------------------------------------------------- /assets/images/flags/CH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CH.png -------------------------------------------------------------------------------- /assets/images/flags/CI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CI.png -------------------------------------------------------------------------------- /assets/images/flags/CK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CK.png -------------------------------------------------------------------------------- /assets/images/flags/CL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CL.png -------------------------------------------------------------------------------- /assets/images/flags/CM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CM.png -------------------------------------------------------------------------------- /assets/images/flags/CN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CN.png -------------------------------------------------------------------------------- /assets/images/flags/CO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CO.png -------------------------------------------------------------------------------- /assets/images/flags/CR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CR.png -------------------------------------------------------------------------------- /assets/images/flags/CU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CU.png -------------------------------------------------------------------------------- /assets/images/flags/CV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CV.png -------------------------------------------------------------------------------- /assets/images/flags/CY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CY.png -------------------------------------------------------------------------------- /assets/images/flags/CZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/CZ.png -------------------------------------------------------------------------------- /assets/images/flags/DE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DE.png -------------------------------------------------------------------------------- /assets/images/flags/DJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DJ.png -------------------------------------------------------------------------------- /assets/images/flags/DK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DK.png -------------------------------------------------------------------------------- /assets/images/flags/DM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DM.png -------------------------------------------------------------------------------- /assets/images/flags/DO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DO.png -------------------------------------------------------------------------------- /assets/images/flags/DZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/DZ.png -------------------------------------------------------------------------------- /assets/images/flags/EC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/EC.png -------------------------------------------------------------------------------- /assets/images/flags/EE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/EE.png -------------------------------------------------------------------------------- /assets/images/flags/EG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/EG.png -------------------------------------------------------------------------------- /assets/images/flags/EH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/EH.png -------------------------------------------------------------------------------- /assets/images/flags/ER.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ER.png -------------------------------------------------------------------------------- /assets/images/flags/ES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ES.png -------------------------------------------------------------------------------- /assets/images/flags/ET.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ET.png -------------------------------------------------------------------------------- /assets/images/flags/EU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/EU.png -------------------------------------------------------------------------------- /assets/images/flags/FI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/FI.png -------------------------------------------------------------------------------- /assets/images/flags/FJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/FJ.png -------------------------------------------------------------------------------- /assets/images/flags/FM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/FM.png -------------------------------------------------------------------------------- /assets/images/flags/FO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/FO.png -------------------------------------------------------------------------------- /assets/images/flags/FR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/FR.png -------------------------------------------------------------------------------- /assets/images/flags/GA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GA.png -------------------------------------------------------------------------------- /assets/images/flags/GB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GB.png -------------------------------------------------------------------------------- /assets/images/flags/GD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GD.png -------------------------------------------------------------------------------- /assets/images/flags/GE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GE.png -------------------------------------------------------------------------------- /assets/images/flags/GG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GG.png -------------------------------------------------------------------------------- /assets/images/flags/GH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GH.png -------------------------------------------------------------------------------- /assets/images/flags/GI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GI.png -------------------------------------------------------------------------------- /assets/images/flags/GL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GL.png -------------------------------------------------------------------------------- /assets/images/flags/GM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GM.png -------------------------------------------------------------------------------- /assets/images/flags/GN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GN.png -------------------------------------------------------------------------------- /assets/images/flags/GP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GP.png -------------------------------------------------------------------------------- /assets/images/flags/GQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GQ.png -------------------------------------------------------------------------------- /assets/images/flags/GR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GR.png -------------------------------------------------------------------------------- /assets/images/flags/GT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GT.png -------------------------------------------------------------------------------- /assets/images/flags/GU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GU.png -------------------------------------------------------------------------------- /assets/images/flags/GW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GW.png -------------------------------------------------------------------------------- /assets/images/flags/GY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/GY.png -------------------------------------------------------------------------------- /assets/images/flags/HK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/HK.png -------------------------------------------------------------------------------- /assets/images/flags/HN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/HN.png -------------------------------------------------------------------------------- /assets/images/flags/HR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/HR.png -------------------------------------------------------------------------------- /assets/images/flags/HT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/HT.png -------------------------------------------------------------------------------- /assets/images/flags/HU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/HU.png -------------------------------------------------------------------------------- /assets/images/flags/ID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ID.png -------------------------------------------------------------------------------- /assets/images/flags/IE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IE.png -------------------------------------------------------------------------------- /assets/images/flags/IL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IL.png -------------------------------------------------------------------------------- /assets/images/flags/IM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IM.png -------------------------------------------------------------------------------- /assets/images/flags/IN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IN.png -------------------------------------------------------------------------------- /assets/images/flags/IQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IQ.png -------------------------------------------------------------------------------- /assets/images/flags/IR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IR.png -------------------------------------------------------------------------------- /assets/images/flags/IS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IS.png -------------------------------------------------------------------------------- /assets/images/flags/IT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/IT.png -------------------------------------------------------------------------------- /assets/images/flags/JE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/JE.png -------------------------------------------------------------------------------- /assets/images/flags/JM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/JM.png -------------------------------------------------------------------------------- /assets/images/flags/JO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/JO.png -------------------------------------------------------------------------------- /assets/images/flags/JP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/JP.png -------------------------------------------------------------------------------- /assets/images/flags/KE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KE.png -------------------------------------------------------------------------------- /assets/images/flags/KG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KG.png -------------------------------------------------------------------------------- /assets/images/flags/KH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KH.png -------------------------------------------------------------------------------- /assets/images/flags/KI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KI.png -------------------------------------------------------------------------------- /assets/images/flags/KM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KM.png -------------------------------------------------------------------------------- /assets/images/flags/KN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KN.png -------------------------------------------------------------------------------- /assets/images/flags/KP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KP.png -------------------------------------------------------------------------------- /assets/images/flags/KR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KR.png -------------------------------------------------------------------------------- /assets/images/flags/KW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KW.png -------------------------------------------------------------------------------- /assets/images/flags/KY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KY.png -------------------------------------------------------------------------------- /assets/images/flags/KZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/KZ.png -------------------------------------------------------------------------------- /assets/images/flags/LA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LA.png -------------------------------------------------------------------------------- /assets/images/flags/LB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LB.png -------------------------------------------------------------------------------- /assets/images/flags/LC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LC.png -------------------------------------------------------------------------------- /assets/images/flags/LI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LI.png -------------------------------------------------------------------------------- /assets/images/flags/LK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LK.png -------------------------------------------------------------------------------- /assets/images/flags/LR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LR.png -------------------------------------------------------------------------------- /assets/images/flags/LS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LS.png -------------------------------------------------------------------------------- /assets/images/flags/LT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LT.png -------------------------------------------------------------------------------- /assets/images/flags/LU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LU.png -------------------------------------------------------------------------------- /assets/images/flags/LV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LV.png -------------------------------------------------------------------------------- /assets/images/flags/LY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/LY.png -------------------------------------------------------------------------------- /assets/images/flags/MA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MA.png -------------------------------------------------------------------------------- /assets/images/flags/MC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MC.png -------------------------------------------------------------------------------- /assets/images/flags/MD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MD.png -------------------------------------------------------------------------------- /assets/images/flags/ME.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ME.png -------------------------------------------------------------------------------- /assets/images/flags/MG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MG.png -------------------------------------------------------------------------------- /assets/images/flags/MH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MH.png -------------------------------------------------------------------------------- /assets/images/flags/MK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MK.png -------------------------------------------------------------------------------- /assets/images/flags/ML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ML.png -------------------------------------------------------------------------------- /assets/images/flags/MM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MM.png -------------------------------------------------------------------------------- /assets/images/flags/MN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MN.png -------------------------------------------------------------------------------- /assets/images/flags/MO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MO.png -------------------------------------------------------------------------------- /assets/images/flags/MQ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MQ.png -------------------------------------------------------------------------------- /assets/images/flags/MR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MR.png -------------------------------------------------------------------------------- /assets/images/flags/MS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MS.png -------------------------------------------------------------------------------- /assets/images/flags/MT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MT.png -------------------------------------------------------------------------------- /assets/images/flags/MU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MU.png -------------------------------------------------------------------------------- /assets/images/flags/MV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MV.png -------------------------------------------------------------------------------- /assets/images/flags/MW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MW.png -------------------------------------------------------------------------------- /assets/images/flags/MX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MX.png -------------------------------------------------------------------------------- /assets/images/flags/MY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MY.png -------------------------------------------------------------------------------- /assets/images/flags/MZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/MZ.png -------------------------------------------------------------------------------- /assets/images/flags/NA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NA.png -------------------------------------------------------------------------------- /assets/images/flags/NC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NC.png -------------------------------------------------------------------------------- /assets/images/flags/NE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NE.png -------------------------------------------------------------------------------- /assets/images/flags/NG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NG.png -------------------------------------------------------------------------------- /assets/images/flags/NI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NI.png -------------------------------------------------------------------------------- /assets/images/flags/NL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NL.png -------------------------------------------------------------------------------- /assets/images/flags/NO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NO.png -------------------------------------------------------------------------------- /assets/images/flags/NP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NP.png -------------------------------------------------------------------------------- /assets/images/flags/NR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NR.png -------------------------------------------------------------------------------- /assets/images/flags/NZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/NZ.png -------------------------------------------------------------------------------- /assets/images/flags/OM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/OM.png -------------------------------------------------------------------------------- /assets/images/flags/PA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PA.png -------------------------------------------------------------------------------- /assets/images/flags/PE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PE.png -------------------------------------------------------------------------------- /assets/images/flags/PF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PF.png -------------------------------------------------------------------------------- /assets/images/flags/PG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PG.png -------------------------------------------------------------------------------- /assets/images/flags/PH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PH.png -------------------------------------------------------------------------------- /assets/images/flags/PK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PK.png -------------------------------------------------------------------------------- /assets/images/flags/PL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PL.png -------------------------------------------------------------------------------- /assets/images/flags/PR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PR.png -------------------------------------------------------------------------------- /assets/images/flags/PS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PS.png -------------------------------------------------------------------------------- /assets/images/flags/PT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PT.png -------------------------------------------------------------------------------- /assets/images/flags/PW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PW.png -------------------------------------------------------------------------------- /assets/images/flags/PY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/PY.png -------------------------------------------------------------------------------- /assets/images/flags/QA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/QA.png -------------------------------------------------------------------------------- /assets/images/flags/RE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/RE.png -------------------------------------------------------------------------------- /assets/images/flags/RO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/RO.png -------------------------------------------------------------------------------- /assets/images/flags/RS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/RS.png -------------------------------------------------------------------------------- /assets/images/flags/RU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/RU.png -------------------------------------------------------------------------------- /assets/images/flags/RW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/RW.png -------------------------------------------------------------------------------- /assets/images/flags/SA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SA.png -------------------------------------------------------------------------------- /assets/images/flags/SB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SB.png -------------------------------------------------------------------------------- /assets/images/flags/SC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SC.png -------------------------------------------------------------------------------- /assets/images/flags/SD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SD.png -------------------------------------------------------------------------------- /assets/images/flags/SE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SE.png -------------------------------------------------------------------------------- /assets/images/flags/SG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SG.png -------------------------------------------------------------------------------- /assets/images/flags/SI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SI.png -------------------------------------------------------------------------------- /assets/images/flags/SK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SK.png -------------------------------------------------------------------------------- /assets/images/flags/SL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SL.png -------------------------------------------------------------------------------- /assets/images/flags/SM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SM.png -------------------------------------------------------------------------------- /assets/images/flags/SN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SN.png -------------------------------------------------------------------------------- /assets/images/flags/SO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SO.png -------------------------------------------------------------------------------- /assets/images/flags/SR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SR.png -------------------------------------------------------------------------------- /assets/images/flags/ST.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ST.png -------------------------------------------------------------------------------- /assets/images/flags/SV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SV.png -------------------------------------------------------------------------------- /assets/images/flags/SY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SY.png -------------------------------------------------------------------------------- /assets/images/flags/SZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/SZ.png -------------------------------------------------------------------------------- /assets/images/flags/TC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TC.png -------------------------------------------------------------------------------- /assets/images/flags/TD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TD.png -------------------------------------------------------------------------------- /assets/images/flags/TG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TG.png -------------------------------------------------------------------------------- /assets/images/flags/TH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TH.png -------------------------------------------------------------------------------- /assets/images/flags/TJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TJ.png -------------------------------------------------------------------------------- /assets/images/flags/TL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TL.png -------------------------------------------------------------------------------- /assets/images/flags/TM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TM.png -------------------------------------------------------------------------------- /assets/images/flags/TN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TN.png -------------------------------------------------------------------------------- /assets/images/flags/TO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TO.png -------------------------------------------------------------------------------- /assets/images/flags/TR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TR.png -------------------------------------------------------------------------------- /assets/images/flags/TT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TT.png -------------------------------------------------------------------------------- /assets/images/flags/TV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TV.png -------------------------------------------------------------------------------- /assets/images/flags/TW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TW.png -------------------------------------------------------------------------------- /assets/images/flags/TZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/TZ.png -------------------------------------------------------------------------------- /assets/images/flags/UA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/UA.png -------------------------------------------------------------------------------- /assets/images/flags/UG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/UG.png -------------------------------------------------------------------------------- /assets/images/flags/US.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/US.png -------------------------------------------------------------------------------- /assets/images/flags/UY.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/UY.png -------------------------------------------------------------------------------- /assets/images/flags/UZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/UZ.png -------------------------------------------------------------------------------- /assets/images/flags/VA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VA.png -------------------------------------------------------------------------------- /assets/images/flags/VC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VC.png -------------------------------------------------------------------------------- /assets/images/flags/VE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VE.png -------------------------------------------------------------------------------- /assets/images/flags/VG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VG.png -------------------------------------------------------------------------------- /assets/images/flags/VI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VI.png -------------------------------------------------------------------------------- /assets/images/flags/VN.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VN.png -------------------------------------------------------------------------------- /assets/images/flags/VU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/VU.png -------------------------------------------------------------------------------- /assets/images/flags/WS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/WS.png -------------------------------------------------------------------------------- /assets/images/flags/YE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/YE.png -------------------------------------------------------------------------------- /assets/images/flags/ZA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ZA.png -------------------------------------------------------------------------------- /assets/images/flags/ZM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ZM.png -------------------------------------------------------------------------------- /assets/images/flags/ZW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/flags/ZW.png -------------------------------------------------------------------------------- /assets/images/icons/mp5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/icons/mp5.png -------------------------------------------------------------------------------- /assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /assets/images/icons/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/icons/flag.png -------------------------------------------------------------------------------- /assets/images/icons/skull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/icons/skull.png -------------------------------------------------------------------------------- /assets/images/mapshots/ot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ot.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ow.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ra.jpg -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /assets/images/213425634sad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/213425634sad.png -------------------------------------------------------------------------------- /assets/images/icons/backstab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/icons/backstab.png -------------------------------------------------------------------------------- /assets/images/mapshots/abbey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/abbey.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/abyss.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/abyss.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/alloy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/alloy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/antel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/antel.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/aod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/aod.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/bklyn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/bklyn.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/campo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/campo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/casa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/casa.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/clash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/clash.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/croma.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/croma.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/depot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/depot.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/disc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/disc.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dock.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/donya.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/donya.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/douze.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/douze.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/duel5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/duel5.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/duel7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/duel7.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/duel8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/duel8.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dune.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dune.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/duomo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/duomo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dust2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dust2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dust4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dust4.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dust6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dust6.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/elegy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/elegy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/eris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/eris.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/exist.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/exist.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/exo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/exo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fc3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fc3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fc4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fc4.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fc5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fc5.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fdm6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fdm6.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/force.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/force.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/forge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/forge.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/frag2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/frag2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fury.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fury.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/gorge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/gorge.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/gubo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/gubo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hades.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hades.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hallo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hallo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hashi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hashi.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/haste.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/haste.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hator.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/haze.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/haze.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hdm3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hdm3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hog2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hog2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/horus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/horus.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/idris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/idris.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kffa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kffa.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kiryu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kiryu.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kmap5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kmap5.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ks2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ks2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/l_ctf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/l_ctf.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/lost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/lost.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/luna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/luna.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mach2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mach2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/maple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/maple.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/masdm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/masdm.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt10.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt12.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt4.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mbt9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mbt9.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/metl2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/metl2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/metl3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/metl3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/metl4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/metl4.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mill.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mill.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nitro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nitro.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nmp4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nmp4.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nmp8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nmp8.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nmp9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nmp9.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/oasis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/oasis.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/orbe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/orbe.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/orion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/orion.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/park.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/park.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/pgdm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/pgdm.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/regal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/regal.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/relic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/relic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/risk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/risk.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/rkc2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/rkc2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/rm1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/rm1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/rm5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/rm5.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ruby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ruby.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ruine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ruine.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/rust.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/rust.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sdm1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sdm1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shiva.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shiva.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/siege.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/siege.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/souls.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/souls.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/spcr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/spcr.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/spcr2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/spcr2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/star.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/star.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/surge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/surge.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tejen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tejen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/thor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/thor.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tubes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tubes.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/wake5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/wake5.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/waltz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/waltz.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/wdcd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/wdcd.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/xenon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/xenon.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/zdm2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/zdm2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ztn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ztn.jpg -------------------------------------------------------------------------------- /assets/images/icons/crosshair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/icons/crosshair.png -------------------------------------------------------------------------------- /assets/images/mapshots/DM_BS1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/DM_BS1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/aard3c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/aard3c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/academy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/academy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/access.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/access.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/alithia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/alithia.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/anubis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/anubis.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/arabic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/arabic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/arbana.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/arbana.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/asgard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/asgard.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/asthma.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/asthma.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/autumn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/autumn.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/averas.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/averas.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/awoken.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/awoken.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/bvdm_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/bvdm_01.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/c_egypt.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/c_egypt.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/canyon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/canyon.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/carbide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/carbide.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/cartel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/cartel.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/catch22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/catch22.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/collide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/collide.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/colony.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/colony.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/complex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/complex.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/crnsp1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/crnsp1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/crust1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/crust1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/crust2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/crust2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/crypta.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/crypta.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/curvedm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/curvedm.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/daemex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/daemex.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/destiny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/destiny.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dispute.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dispute.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/enigma.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/enigma.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fallen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fallen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/frozen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/frozen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fubuki.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fubuki.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fusion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fusion.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/garden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/garden.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/genesis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/genesis.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ghetto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ghetto.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hektik.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hektik.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hidden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hidden.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/idyll3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/idyll3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/infamy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/infamy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/insipid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/insipid.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/island.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/island.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/janela.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/janela.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/justice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/justice.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/k_rpg1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/k_rpg1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kastro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kastro.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ksauer1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ksauer1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ladder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ladder.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/laucin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/laucin.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/legacy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/legacy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/legazzo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/legazzo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/level9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/level9.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mc-lab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mc-lab.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/memento.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/memento.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/memoria.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/memoria.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mercury.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mercury.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp10.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp6a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp6a.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp6b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp6b.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp6c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp6c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp9a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp9a.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp9b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp9b.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/mpsp9c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/mpsp9c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nessus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nessus.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nevil_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nevil_c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nucleus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nucleus.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ognjen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ognjen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/osiris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/osiris.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/outpost.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/outpost.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/pandora.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/pandora.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/pariah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/pariah.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/pul1ctf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/pul1ctf.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/refuge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/refuge.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/reissen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/reissen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/river_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/river_c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/rpg_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/rpg_01.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ruebli.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ruebli.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/saffier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/saffier.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shindou.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shindou.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/siberia.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/siberia.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/skrdm1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/skrdm1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/skrsp1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/skrsp1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/spiralz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/spiralz.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/stadium.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/stadium.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/stemple.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/stemple.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/stolen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/stolen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/suburb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/suburb.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/suisei.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/suisei.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tartech.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tartech.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tempest.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tempest.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/torment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/torment.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tortuga.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tortuga.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tumwalk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tumwalk.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/turbine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/turbine.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/turmoil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/turmoil.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/unworld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/unworld.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/urban_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/urban_c.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/venice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/venice.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/warlock.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/warlock.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/zavial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/zavial.jpg -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /assets/images/mapshots/akaritori.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/akaritori.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/akimiski.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/akimiski.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/akroseum.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/akroseum.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/albatross.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/albatross.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/aqueducts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/aqueducts.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/asenatra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/asenatra.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/asteroids.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/asteroids.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/authentic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/authentic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/bad_moon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/bad_moon.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/box_demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/box_demo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/breakout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/breakout.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/bt_falls.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/bt_falls.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/c_valley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/c_valley.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/caribbean.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/caribbean.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/collusion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/collusion.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/conflict.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/conflict.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/corruption.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/corruption.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ctf_suite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ctf_suite.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/cwcastle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/cwcastle.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/damnation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/damnation.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/darkdeath.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/darkdeath.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/deathtek.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/deathtek.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dirtndust.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dirtndust.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/disruption.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/disruption.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/door_demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/door_demo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/dopamine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/dopamine.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/earthsea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/earthsea.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/europium.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/europium.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/evilness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/evilness.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ex_example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ex_example.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fb_capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fb_capture.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ferguson.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ferguson.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fire_keep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fire_keep.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/flagstone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/flagstone.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/forgotten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/forgotten.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fortress.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fortress.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/frag-lab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/frag-lab.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fragnostic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fragnostic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fragplaza.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fragplaza.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/frostbyte.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/frostbyte.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/frozen6a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/frozen6a.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/gothic-df.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/gothic-df.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/guacamole.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/guacamole.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/gunmetal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/gunmetal.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/headroom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/headroom.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/helligsted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/helligsted.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hillfort.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hillfort.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/industry.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/industry.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/infernal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/infernal.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/injustice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/injustice.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kalking1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kalking1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/katrez_d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/katrez_d.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/killcore3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/killcore3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/konkuri-to.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/konkuri-to.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/kopenhagen.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/kopenhagen.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/lost_soul.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/lost_soul.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/lost_world.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/lost_world.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/meltdown2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/meltdown2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/memento2b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/memento2b.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/monastery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/monastery.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/moonlite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/moonlite.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/neonpanic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/neonpanic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/nevil_c2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/nevil_c2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/new_energy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/new_energy.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/oddworld.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/oddworld.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ogrosupply.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ogrosupply.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/oldschool.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/oldschool.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/overdrive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/overdrive.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/paradigm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/paradigm.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ph-capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ph-capture.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/phosgene.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/phosgene.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/phrantic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/phrantic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/powerplant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/powerplant.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/purgatory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/purgatory.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/recovery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/recovery.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/redemption.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/redemption.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/renegade.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/renegade.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/river_keep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/river_keep.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/roughinery.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/roughinery.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sacrifice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sacrifice.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sandstorm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sandstorm.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sandstorm2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sandstorm2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sauerowalk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sauerowalk.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/serenity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/serenity.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shadowed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shadowed.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shinmei1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shinmei1.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shipwreck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shipwreck.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/simplicity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/simplicity.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/stahlbox.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/stahlbox.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/stronghold.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/stronghold.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/subterra.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/subterra.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tatooine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tatooine.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/teahupoo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/teahupoo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/tectonic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/tectonic.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/thetowers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/thetowers.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/toxicity.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/toxicity.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/triforts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/triforts.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/turbulence.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/turbulence.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/twinforts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/twinforts.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/unworld2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/unworld2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/unworld3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/unworld3.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/valhalla.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/valhalla.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/ventania.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/ventania.jpg -------------------------------------------------------------------------------- /assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /assets/images/mapshots/berlin_wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/berlin_wall.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/castle_trap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/castle_trap.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/core_refuge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/core_refuge.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/curvy_castle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/curvy_castle.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/desecration.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/desecration.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/earthstation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/earthstation.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/face-capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/face-capture.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/firstevermap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/firstevermap.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/killfactory.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/killfactory.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/lostinspace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/lostinspace.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/pitch_black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/pitch_black.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sauerbraten.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sauerbraten.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/sauerstruck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/sauerstruck.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/shellshock2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/shellshock2.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/capture_night.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/capture_night.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/core_transfer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/core_transfer.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/eternal_valley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/eternal_valley.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/fanatic_quake.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/fanatic_quake.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/hiddenfortress.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/hiddenfortress.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/neondevastation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/neondevastation.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/platform_demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/platform_demo.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/secondevermap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/secondevermap.jpg -------------------------------------------------------------------------------- /assets/images/mapshots/snapper_rocks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AngrySnout/SauerTracker/HEAD/assets/images/mapshots/snapper_rocks.jpg -------------------------------------------------------------------------------- /assets/images/convert.sh: -------------------------------------------------------------------------------- 1 | for file in mapshots_tmp/*.jpg 2 | do 3 | gm convert -resize 1024x1024! -blur 50x4 "$file" "${file/mapshots_tmp/mapshots_out}" 4 | done 5 | 6 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./wait-for-it.sh postgres:5432 4 | 5 | if [ "$1" = 'start' ]; then 6 | yarn migrate 7 | yarn start 8 | fi 9 | 10 | exec yarn $@ 11 | -------------------------------------------------------------------------------- /src/api/v2/main.js: -------------------------------------------------------------------------------- 1 | require('./servers'); 2 | require('./server'); 3 | require('./games'); 4 | require('./game'); 5 | require('./players'); 6 | require('./player'); 7 | require('./clans'); 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | node_modules/ 3 | build/ 4 | assets/js/ 5 | tmp/ 6 | coverage/ 7 | esdoc/ 8 | config.json 9 | src/web/compat.js 10 | npm-debug.log 11 | logs/ 12 | dist/ 13 | -------------------------------------------------------------------------------- /src/api/v1/main.js: -------------------------------------------------------------------------------- 1 | require('./servers'); 2 | require('./server'); 3 | require('./games'); 4 | require('./game'); 5 | require('./players'); 6 | require('./player'); 7 | require('./clans'); 8 | require('./clan'); 9 | -------------------------------------------------------------------------------- /website/views/empty.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block content 4 | .row.main-container 5 | ul.breadcrumbs 6 | li.current= title 7 | .medium-12.columns.end 8 | != content 9 | -------------------------------------------------------------------------------- /assets/images/icons/LICENSE: -------------------------------------------------------------------------------- 1 | All icons in this directory are licensed under CC BY 3.0 and available on http://game-icons.net. 2 | 3 | Credits: 4 | backstab.png, flag.png, skull.png: Lorc 5 | crosshair.ong, mp5.png: Delapouite 6 | 7 | -------------------------------------------------------------------------------- /knexfile.js: -------------------------------------------------------------------------------- 1 | const database = { 2 | client: 'pg', 3 | connection: process.env.DATABASE_URL, 4 | searchPath: ['knex', 'public'], 5 | }; 6 | 7 | module.exports = { 8 | development: database, 9 | production: database, 10 | }; 11 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | node_modules/ 3 | build/ 4 | assets/js/ 5 | tmp/ 6 | coverage/ 7 | esdoc/ 8 | config.json 9 | src/web/compat.js 10 | npm-debug.log 11 | logs/ 12 | dist/ 13 | docker-compose.yml 14 | Dockerfile 15 | pgdata/ 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:13 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY package*.json ./ 6 | 7 | RUN yarn install 8 | 9 | COPY . . 10 | 11 | RUN yarn build 12 | 13 | EXPOSE 8080 14 | 15 | ENTRYPOINT [ "docker-entrypoint.sh" ] 16 | 17 | CMD [ "start" ] 18 | -------------------------------------------------------------------------------- /src/util/database.js: -------------------------------------------------------------------------------- 1 | import knex from 'knex'; 2 | 3 | import { getDatabaseURL } from '../util/config'; 4 | 5 | const database = knex({ 6 | client: 'pg', 7 | connection: getDatabaseURL(), 8 | searchPath: ['knex', 'public'], 9 | }); 10 | export default database; 11 | -------------------------------------------------------------------------------- /src/web/banners.js: -------------------------------------------------------------------------------- 1 | import app from '../util/web'; 2 | import vars from '../../vars.json'; 3 | import bannersTemplate from '../../website/views/banners.pug'; 4 | 5 | app.get('/banners', (req, res) => { 6 | res.send(bannersTemplate({ query: req.query, bannerURL: vars.bannerURL })); 7 | }); 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import startTeamBalanceServer from './api/team-balance'; 2 | 3 | require('./tracker/server-manager').default.start(); 4 | require('./tracker/player-manager').default.start(); 5 | 6 | require('./tracker/master').start(); 7 | 8 | require('./web'); 9 | startTeamBalanceServer(); 10 | -------------------------------------------------------------------------------- /src/web/metrics.js: -------------------------------------------------------------------------------- 1 | import app from '../util/web'; 2 | import { getAllMetrics } from '../util/metrics'; 3 | import metricsTemplate from '../../website/views/metrics.pug'; 4 | 5 | app.get('/metrics', (req, res) => { 6 | getAllMetrics().then(metrics => { 7 | res.send(metricsTemplate({ metrics })); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /migrations/20160510143720_remove_server_keep.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.schema.table('servers', function (table) { 4 | table.dropColumn('keep'); 5 | }); 6 | }; 7 | 8 | exports.down = function(knex, Promise) { 9 | return knex.schema.table('servers', function (table) { 10 | table.boolean('keep'); 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /migrations/20171007201942_unique_players_name.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.schema.table('players', function (table) { 4 | table.unique('name'); 5 | }); 6 | }; 7 | 8 | exports.down = function(knex, Promise) { 9 | return knex.schema.table('players', function (table) { 10 | table.dropUnique('name'); 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /src/web/index.js: -------------------------------------------------------------------------------- 1 | require('../api/v1/main'); 2 | require('../api/v2/main'); 3 | 4 | require('./about'); 5 | require('./servers'); 6 | require('./server'); 7 | require('./metrics'); 8 | require('./games'); 9 | require('./game'); 10 | require('./players'); 11 | require('./player'); 12 | require('./clans'); 13 | require('./clan'); 14 | require('./stats'); 15 | require('./banners'); 16 | -------------------------------------------------------------------------------- /website/views/_partials/clans-online.pug: -------------------------------------------------------------------------------- 1 | if clansOnline && clansOnline.length 2 | label.big Clans online: 3 | for clan in clansOnline 4 | a(title=(clan.players.join(" \n")), onclick=("findPlayer('"+clan.name.replace(/\'/g, "\\'")+"')")) #{clan.name} 5 | | 6 | span.label.secondary(style="margin-top: -5px;") #{clan.count} 7 | | 8 | -------------------------------------------------------------------------------- /src/util/redis.js: -------------------------------------------------------------------------------- 1 | import redis from 'redis'; 2 | import Promise from 'bluebird'; 3 | 4 | import { logError } from './util'; 5 | import { getRedisURL } from './config'; 6 | 7 | Promise.promisifyAll(redis.RedisClient.prototype); 8 | Promise.promisifyAll(redis.Multi.prototype); 9 | 10 | 11 | const client = redis.createClient({ 12 | url: getRedisURL() 13 | }); 14 | export default client; 15 | 16 | client.on('error', (err) => { 17 | logError(err); 18 | }); 19 | -------------------------------------------------------------------------------- /migrations/20180215000343_delete_requests_table.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.schema.dropTable('requests'); 4 | }; 5 | 6 | exports.down = function(knex, Promise) { 7 | return knex.schema.createTableIfNotExists('requests', function (table) { 8 | table.increments(); 9 | table.string('method'); 10 | table.string('ip'); 11 | table.text('url'); 12 | table.float('time'); 13 | table.dateTime('timestamp').defaultTo(knex.fn.now()); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /src/api/v2/servers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | import Promise from 'bluebird'; 3 | 4 | import app from '../../util/web'; 5 | import cache from '../../util/cache'; 6 | import serverManager from '../../tracker/server-manager'; 7 | import redis from '../../util/redis'; 8 | 9 | app.get('/api/v2/servers', (req, res) => { 10 | redis.getAsync('server-list') 11 | .then((list) => { 12 | const servers = JSON.parse(list); 13 | res.send(servers); 14 | }) 15 | .catch((err) => { res.status(500).send({ error: err }); }); 16 | }); 17 | -------------------------------------------------------------------------------- /migrations/20180214035158_update_players_schema.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.raw('ALTER TABLE players ADD COLUMN "accFrags" double precision; UPDATE players SET "accFrags" = players.acc * players.frags') 4 | .then(() => knex.schema.table('players', function (table) { 5 | table.dropColumn('countryName'); 6 | table.dropColumn('acc'); 7 | table.dropColumn('kpd'); 8 | })); 9 | }; 10 | 11 | exports.down = function(knex, Promise) { 12 | return knex.schema.table('players', function (table) { 13 | table.dropColumn('accFrags'); 14 | table.text('countryName'); 15 | table.float('acc'); 16 | table.float('kpd'); 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /website/views/stats.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = "home"; 5 | - title = "Stats"; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li.current= title 11 | .medium-12.columns.end 12 | label.big Last 7 days' statistics: 13 | table 14 | thead 15 | tr 16 | td(width="25%") Day 17 | td(width="25%", style="text-align: right;") Games 18 | tbody 19 | for day in stats 20 | tr 21 | td= (day.date==today)? "Today": ((day.date==yesterday)? "Yesterday": day.date) 22 | td(style="text-align: right;")= day.games||0 23 | -------------------------------------------------------------------------------- /src/web/servers.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import vars from '../../vars.json'; 4 | 5 | import app from '../util/web'; 6 | import redis from '../util/redis'; 7 | import serversTemplate from '../../website/views/servers.pug'; 8 | 9 | app.get('/', (req, res) => { 10 | redis 11 | .getAsync('server-list') 12 | .then(list => { 13 | res.send( 14 | serversTemplate({ 15 | servers: _.orderBy(list ? JSON.parse(list) : [], 'clients', 'desc'), 16 | sortedBy: 'clients', 17 | sortOrder: 'desc', 18 | vars, 19 | noBanner: req.query.banner === 'no', 20 | }) 21 | ); 22 | }) 23 | .catch(err => { 24 | res.status(500).send({ error: err.message }); 25 | }); 26 | }); 27 | 28 | app.get('/servers', (req, res) => { 29 | res.redirect('/'); 30 | }); 31 | -------------------------------------------------------------------------------- /src/web/clan.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import vars from '../../vars.json'; 4 | 5 | import app from '../util/web'; 6 | import { logError, ObjectNotFoundError } from '../util/util'; 7 | import { getClan } from '../api/v1/clan'; 8 | import clanTemplate from '../../website/views/clan.pug'; 9 | 10 | app.get('/clan/:name', (req, res) => { 11 | getClan(req.params.name) 12 | .then(result => { 13 | res.send( 14 | clanTemplate(_.assign(result, { bannerURL: vars.bannerURL, _ })) 15 | ); 16 | }) 17 | .catch(ObjectNotFoundError, () => { 18 | res 19 | .status(404) 20 | .render('error', { status: 404, error: 'Clan not found.' }); 21 | }) 22 | .catch(err => { 23 | logError(err); 24 | res.status(500).render('error', { status: 500, error: err.message }); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/web/game.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import vars from '../../vars.json'; 4 | 5 | import app from '../util/web'; 6 | import { ObjectNotFoundError } from '../util/util'; 7 | import { getGame } from '../api/v1/game'; 8 | import gameTemplate from '../../website/views/game.pug'; 9 | 10 | app.get('/game/:id', (req, res) => { 11 | getGame(req.params.id) 12 | .then(result => { 13 | res.send( 14 | gameTemplate({ 15 | id: req.params.id, 16 | server: result, 17 | _, 18 | vars, 19 | }) 20 | ); 21 | }) 22 | .catch(ObjectNotFoundError, () => { 23 | res 24 | .status(404) 25 | .render('error', { status: 404, error: 'Game not found.' }); 26 | }) 27 | .catch(err => { 28 | res.status(500).render('error', { status: 500, error: err.message }); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /website/views/profile.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = "players"; 5 | - title = "Profile"; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li.current Profile 11 | .medium-12.columns 12 | if names && names.length 13 | | Possible names for your IP address (#{ip}) are: 14 | div(style="margin-left: 3em") 15 | for name in names 16 | a(href=("/player/"+encodeURIComponent(name)))= name 17 | br 18 | br 19 | | None of these are you? Try searching for your name on the players page. 20 | else 21 | | No names found for your IP address. You can search for your name on the players page. 22 | -------------------------------------------------------------------------------- /src/util/country.js: -------------------------------------------------------------------------------- 1 | import ip2loc from 'ip2location-nodejs'; 2 | import countries from 'i18n-iso-countries'; 3 | 4 | ip2loc.IP2Location_init('./IP2LOCATION-LITE-DB1.BIN'); 5 | 6 | export function formatIP(ipInt) { 7 | return ( 8 | (ipInt >>> 24) + 9 | '.' + 10 | ((ipInt >> 16) & 255) + 11 | '.' + 12 | ((ipInt >> 8) & 255) + 13 | '.' + 14 | (ipInt & 255) 15 | ); 16 | } 17 | 18 | export default function getCountry(ip) { 19 | if (ip === '2.16.6.0') return 'DE'; 20 | 21 | const country = ip2loc.IP2Location_get_country_short(ip); 22 | if (country === '?' || country === '-') return ''; 23 | return country; 24 | } 25 | 26 | export function getCountryName(countryCode) { 27 | if (countryCode === 'US') { 28 | return 'United States'; // Instead of United States of America 29 | } 30 | return countries.getName(countryCode, 'en'); 31 | } 32 | -------------------------------------------------------------------------------- /website/js/game.js: -------------------------------------------------------------------------------- 1 | const $ = window.jQuery; 2 | 3 | import similarGamesTemplate from 'pug-loader!../views/_partials/similar-games.pug'; 4 | 5 | const mapName = $('#map-name').text(); 6 | const gameType = $('#game-type').text(); 7 | 8 | window.tryLoadBackground(mapName); 9 | 10 | function loadSimilarGames() { 11 | if (gameType === 'duel' || gameType === 'clanwar') { 12 | const meta = JSON.parse($('#game-meta').text()); 13 | const query = `/games/find?gametype=${gameType}&limit=10&players=${meta[0]} ${meta[2]}`; 14 | $.get(`/api${query}`, result => { 15 | $('#similar-games').html( 16 | similarGamesTemplate({ 17 | similarGames: result.results, 18 | viewAllLink: query, 19 | }) 20 | ); 21 | $('#similar-games-parent').css('display', 'block'); 22 | disableDefault(); 23 | }); 24 | } 25 | } 26 | loadSimilarGames(); 27 | -------------------------------------------------------------------------------- /src/tracker/spy.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import moment from 'moment'; 3 | 4 | import database from '../util/database'; 5 | 6 | let players = {}; 7 | 8 | export function addPlayerSpy(name, ip, country, server) { 9 | if (!players[name]) players[name] = {}; 10 | players[name][ip] = { 11 | country, 12 | host: server.host, 13 | port: server.port, 14 | time: moment().format('YYYY-MM-DD HH:mm:ss'), 15 | }; 16 | } 17 | 18 | export function saveSpy() { 19 | const oldPlayer = players; 20 | players = {}; 21 | return _.map(oldPlayer, (player, name) => _.map(player, (info, ip) => database.raw('insert into spy (name, ip, country, lastseen, lshost, lsport) values (?, ?, ?, ?, ?, ?) on conflict (name, ip) do update set country = excluded.country, lastseen = excluded.lastseen, lshost = excluded.lshost, lsport = excluded.lsport', [name, ip, info.country, info.time, info.host, info.port]).then())); 22 | } 23 | -------------------------------------------------------------------------------- /src/web/server.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import vars from '../../vars.json'; 4 | import app from '../util/web'; 5 | import { ObjectNotFoundError } from '../util/util'; 6 | import { findServer } from '../api/v1/server'; 7 | import serverTemplate from '../../website/views/server.pug'; 8 | 9 | app.get('/server/:host/:port', (req, res) => { 10 | findServer(req.params.host, req.params.port) 11 | .then(server => { 12 | res.send( 13 | serverTemplate({ 14 | server, 15 | vars, 16 | _, 17 | bannerURL: vars.bannerURL, 18 | }) 19 | ); 20 | }) 21 | .catch(ObjectNotFoundError, () => { 22 | res 23 | .status(404) 24 | .render('error', { status: 404, error: 'Server not found.' }); 25 | }) 26 | .catch(err => { 27 | res.status(500).render('error', { status: 500, error: err.message }); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/web/stats.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import moment from 'moment'; 3 | 4 | import app from '../util/web'; 5 | import database from '../util/database'; 6 | import statsTemplate from '../../website/views/stats.pug'; 7 | 8 | app.get('/stats', (req, res) => { 9 | const weekAgo = moment() 10 | .endOf('day') 11 | .subtract(7, 'days') 12 | .format('YYYY-MM-DD'); 13 | database 14 | .raw( 15 | `SELECT to_char(timestamp, 'MM-DD') AS date, COUNT(*) AS games FROM games WHERE timestamp > '${weekAgo}' GROUP BY date ORDER BY date DESC` 16 | ) 17 | .then(result => result.rows) 18 | .then(days => { 19 | const stats = _.orderBy(days, 'date', 'desc'); 20 | res.send( 21 | statsTemplate({ 22 | stats, 23 | today: moment().format('MM-DD'), 24 | yesterday: moment() 25 | .subtract(1, 'days') 26 | .format('MM-DD'), 27 | }) 28 | ); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | tracker: 4 | build: . 5 | restart: always 6 | ports: 7 | - 8081:8080 8 | environment: 9 | PORT: 8080 10 | BALANCE_PORT: 36581 11 | DATABASE_URL: 'postgres://SauerTracker:postgrespassword@postgres:5432' 12 | REDIS_URL: 'redis://redis' 13 | BASE_ELO: 1200 14 | MASTER_PORT: 28787 15 | MASTER_HOST: master.sauerbraten.org 16 | NODE_ENV: production 17 | entrypoint: './docker-entrypoint.sh' 18 | command: 'start' 19 | depends_on: 20 | - postgres 21 | - redis 22 | postgres: 23 | image: postgres 24 | restart: always 25 | shm_size: 1gb 26 | volumes: 27 | - ./pgdata:/var/lib/postgresql/data 28 | # - ./dump.sql:/docker-entrypoint-initdb.d/init.sql:ro 29 | environment: 30 | POSTGRES_PASSWORD: postgrespassword 31 | POSTGRES_USER: SauerTracker 32 | redis: 33 | image: redis 34 | restart: always 35 | -------------------------------------------------------------------------------- /src/web/player.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import vars from '../../vars.json'; 4 | 5 | import app from '../util/web'; 6 | import { ObjectNotFoundError, ObjectBannedError } from '../util/util'; 7 | import { getPlayer } from '../api/v1/player'; 8 | import playerTemplate from '../../website/views/player.pug'; 9 | 10 | app.get('/player/:name', (req, res) => { 11 | getPlayer(req.params.name) 12 | .then(result => { 13 | res.send(playerTemplate(_.assign(result, { _, vars }))); 14 | }) 15 | .catch(ObjectNotFoundError, () => { 16 | res 17 | .status(404) 18 | .render('error', { 19 | status: 404, 20 | error: 'No player found with this name.', 21 | }); 22 | }) 23 | .catch(ObjectBannedError, () => { 24 | res 25 | .status(400) 26 | .render('error', { status: 400, error: 'This player name is banned.' }); 27 | }) 28 | .catch(err => { 29 | res.status(500).render('error', { status: 500, error: err.message }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const glob_entries = require('webpack-glob-entries'); 3 | 4 | const serverConfig = { 5 | target: 'node', 6 | entry: { 7 | tracker: './src/index.js', 8 | detectClanwars: './src/scripts/detect-clanwars.js', 9 | recalculateElo: './src/scripts/recalculate-elo.js', 10 | }, 11 | output: { 12 | path: path.resolve(__dirname, 'dist'), 13 | filename: '[name].js', 14 | }, 15 | externals: { 16 | knex: 'commonjs knex', 17 | }, 18 | module: { 19 | rules: [{ test: /\.pug$/, use: 'pug-loader' }], 20 | }, 21 | }; 22 | 23 | const websiteConfig = { 24 | entry: glob_entries('./website/js/[^_]*.js'), 25 | output: { 26 | path: path.resolve(__dirname, 'assets/js'), 27 | filename: '[name].js', 28 | }, 29 | module: { 30 | rules: [{ test: /\.pug/, use: 'pug-loader' }], 31 | rules: [ 32 | { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }, 33 | ], 34 | }, 35 | }; 36 | 37 | module.exports = [serverConfig, websiteConfig]; 38 | -------------------------------------------------------------------------------- /src/util/config.js: -------------------------------------------------------------------------------- 1 | export function getPort() { 2 | const variable = parseInt(process.env.PORT); 3 | return variable ? variable : 8080; 4 | } 5 | 6 | export function getBalancePort() { 7 | const variable = parseInt(process.env.BALANCE_PORT); 8 | return variable ? variable : 36581; 9 | } 10 | 11 | export function getDatabaseURL() { 12 | const variable = process.env.DATABASE_URL; 13 | return variable ? variable : 'postgres://localhost:5432'; 14 | } 15 | 16 | export function getRedisURL() { 17 | const variable = process.env.REDIS_URL; 18 | return variable ? variable : 'redis://localhost:6379'; 19 | } 20 | 21 | export function getBaseElo() { 22 | const variable = parseInt(process.env.BASE_ELO); 23 | return variable ? variable : 1200; 24 | } 25 | 26 | export function getMasterPort() { 27 | const variable = parseInt(process.env.MASTER_PORT); 28 | return variable ? variable : 28787; 29 | } 30 | 31 | export function getMasterHost() { 32 | const variable = process.env.MASTER_HOST; 33 | return variable ? variable : 'sauerbraten.org'; 34 | } 35 | -------------------------------------------------------------------------------- /website/js/server.js: -------------------------------------------------------------------------------- 1 | import { loadCharts } from './_server-charts'; 2 | import url from 'url'; 3 | import _ from 'lodash'; 4 | import vars from '../../vars.json'; 5 | import gameTemplate from 'pug-loader!../views/_partials/game.pug'; 6 | 7 | const $ = window.jQuery; 8 | 9 | const urlPath = url.parse(window.location.href).pathname.split('/'); 10 | const host = urlPath[2]; 11 | const port = parseInt(urlPath[3], 10); 12 | 13 | const $banner = $('#banner'); 14 | const bannerURL = $banner.length ? $banner.attr('src') : null; 15 | 16 | function updateGame() { 17 | $.get(`/api/server/${host}/${port}`, result => { 18 | render(result); 19 | }); 20 | } 21 | setInterval(updateGame, 5000); 22 | 23 | function updateBanner() { 24 | $banner.attr('src', `${bannerURL}#${new Date().getTime()}`); 25 | } 26 | if (bannerURL) setInterval(updateBanner, 10000); 27 | 28 | window.tryLoadBackground($('#map-name').text()); 29 | 30 | loadCharts(host, port); 31 | 32 | function render(game) { 33 | window.tryLoadBackground(game.mapName); 34 | $('#game').html(gameTemplate({ server: game, vars, _ })); 35 | } 36 | -------------------------------------------------------------------------------- /website/views/game.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = "games"; 5 | - title = server.description; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li Games 11 | li.current= id 12 | .medium-12.columns 13 | #game 14 | include ./_partials/game.pug 15 | #similar-games-parent(style="display: none;") 16 | label.big Similar Games 17 | span#game-meta(style="display: none;")= JSON.stringify(server.meta) 18 | span#game-type(style="display: none;")= server.gameType 19 | .row 20 | .large-6.columns 21 | #similar-games 22 | 23 | .reveal#connect-info(data-reveal) 24 | | Copy the following line, paste it in the game, and press Enter to connect to the server: 25 | br 26 | br 27 | input#connect-command(type="text", value="/connect", onfocus="$(this).select()") 28 | 29 | block scripts 30 | script(src="/js/game.js") 31 | -------------------------------------------------------------------------------- /migrations/20171211131355_add_constraints.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return Promise.all([ 4 | knex.raw('DELETE FROM spy a USING spy b WHERE a.id < b.id AND a.name = b.name AND a.ip = b.ip'), 5 | knex.raw('DELETE FROM bans a USING bans b WHERE a.id < b.id AND a.name = b.name AND a.ip = b.ip'), 6 | knex.raw('DELETE FROM servers a USING servers b WHERE a.id < b.id AND a.host = b.host AND a.port = b.port') 7 | ]).then(() => Promise.all([ 8 | knex.schema.table('spy', function (table) { 9 | table.unique(['name', 'ip']); 10 | }), 11 | knex.schema.table('bans', function (table) { 12 | table.unique(['name', 'ip']); 13 | }), 14 | knex.schema.table('servers', function (table) { 15 | table.unique(['host', 'port']); 16 | }) 17 | ])); 18 | }; 19 | 20 | exports.down = function(knex, Promise) { 21 | return Promise.all([ 22 | knex.schema.table('spy', function (table) { 23 | table.dropUnique(['name', 'ip']); 24 | }), 25 | knex.schema.table('bans', function (table) { 26 | table.dropUnique(['name', 'ip']); 27 | }), 28 | knex.schema.table('servers', function (table) { 29 | table.dropUnique(['host', 'port']); 30 | }) 31 | ]); 32 | }; 33 | -------------------------------------------------------------------------------- /src/api/v2/server.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import app from '../../util/web'; 4 | import { ObjectNotFoundError } from '../../util/util'; 5 | 6 | import database from '../../util/database'; 7 | import serverManager from '../../tracker/server-manager'; 8 | 9 | export function findServer(host, port) { 10 | port = parseInt(port, 10); 11 | let server = serverManager.find(host, port); 12 | if (server) { 13 | server = server.serialize(true); 14 | 15 | if (server.teams) server.teams = _.map(server.teams, (score, name) => ({ name, score })); 16 | 17 | return database('serverranks').where({ host, port }).select('count', 'rank').then((result) => { 18 | if (result.length) { 19 | server.totalGames = result[0].count; 20 | server.rank = result[0].rank; 21 | } 22 | return server; 23 | }); 24 | } 25 | return Promise.reject(new ObjectNotFoundError()); 26 | } 27 | 28 | app.get('/api/v2/server/:host/:port', (req, res) => { 29 | findServer(req.params.host, req.params.port) 30 | .then((server) => { res.send(server); }) 31 | .catch(ObjectNotFoundError, () => { res.status(404).send({ error: 'Server not found.' }); }) 32 | .catch((err) => { res.status(500).send({ error: err }); }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/util/protocol.js: -------------------------------------------------------------------------------- 1 | export const gameModes = [ 2 | 'ffa', 3 | 'coop_edit', 4 | 'teamplay', 5 | 'instagib', 6 | 'insta_team', 7 | 'efficiency', 8 | 'effic_team', 9 | 'tactics', 10 | 'tac_team', 11 | 'capture', 12 | 'regen_capture', 13 | 'ctf', 14 | 'insta_ctf', 15 | 'protect', 16 | 'insta_protect', 17 | 'hold', 18 | 'insta_hold', 19 | 'effic_ctf', 20 | 'effic_protect', 21 | 'effic_hold', 22 | 'collect', 23 | 'insta_collect', 24 | 'effic_collect', 25 | ]; 26 | 27 | export const masterModes = [ 28 | 'auth', // -1 29 | 'open', // 0 30 | 'veto', // 1 31 | 'locked', // 2 32 | 'private', // 3 33 | 'password', // 4 34 | ]; 35 | 36 | /** 37 | * Maps game mode number to name, according to protocol 259. 38 | * @param {number} code - The mode number. 39 | * @returns {string} name - Name of the mode. 40 | */ 41 | export function getGameMode(code) { 42 | return gameModes[code] || 'unknown'; 43 | } 44 | 45 | /** 46 | * Maps mastermode number to name, according to protocol 259. 47 | * @param {number} code - The mastermode number. 48 | * @returns {string} name - Name of the mastermode. 49 | */ 50 | export function getMasterMode(code) { 51 | return masterModes[code + 1] || 'unknown'; 52 | } 53 | -------------------------------------------------------------------------------- /website/views/_partials/similar-games.pug: -------------------------------------------------------------------------------- 1 | table.scroll#search-results(width="50%") 2 | thead 3 | tr 4 | td(width="40%") Mode / Map 5 | td.text-center(width="60%") Result 6 | tbody 7 | for game in similarGames 8 | tr.clickable(onclick="if (window.history) { history.pushState({}, window.location.href); } window.location.replace('/game/"+game.id+"')") 9 | td: a.disable-default(href="/game/"+game.id)= game.gamemode + " " + game.map 10 | td: a.disable-default(href="/game/"+game.id) 11 | .row 12 | .small-6.columns(style="text-align: right; padding-right: 10;") 13 | = game.meta[2]+" " 14 | span.label(class=(game.draw? "warning": "success"), style="cursor: pointer") 15 | = game.meta[3] 16 | .small-6.columns(style="text-align: left; padding-right: 10;") 17 | span.label(class=(game.draw? "warning": "alert"), style="cursor: pointer") 18 | = game.meta[1] 19 | = " "+game.meta[0] 20 | tr: td(colspan=2): a(href=viewAllLink) View all... 21 | -------------------------------------------------------------------------------- /website/views/error.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = ""; 5 | - title = "Error "+status; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li.current= "Error "+status 11 | .medium-12.columns 12 | if status===404 13 | h3 Error 404. Page not found. 14 | if error 15 | = error 16 | else 17 | | If you typed the address manually, check your spelling. 18 | br 19 | | If this is a server's page, the server might be down at the moment. Try again at a later time. 20 | else if status===500 21 | h3 Error 500. Internal server error. 22 | | An internal error occurred. Please report this using the links in the footer below. 23 | if error 24 | br 25 | | Error message: 26 | br 27 | br 28 | div(style="margin-left: 2em;") !{error.stack? error.stack.replace(/\n/g, "
"): error} 29 | else 30 | h3= "Error "+status+"." 31 | if error 32 | = error 33 | -------------------------------------------------------------------------------- /src/api/v1/servers.js: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | import _ from 'lodash'; 3 | 4 | import app from '../../util/web'; 5 | import cache from '../../util/cache'; 6 | import serverManager from '../../tracker/server-manager'; 7 | import redis from '../../util/redis'; 8 | 9 | app.get('/api/servers', (req, res) => { 10 | redis.getAsync('server-list') 11 | .then((list) => { res.setHeader('Content-Type', 'application/json'); res.send(list); }) 12 | .catch((err) => { res.status(500).send({ error: err }); }); 13 | }); 14 | 15 | cache.set('server-countries', 5000, () => { 16 | const res = {}; 17 | res.servers = _.countBy(serverManager.list, 'countryName'); 18 | res.players = {}; 19 | res.links = {}; 20 | 21 | _.each(serverManager.list, (server) => { 22 | _.each(_.countBy(server.game.players, 'countryName'), (val, ind) => { 23 | if (ind === 'Unknown') return; 24 | 25 | res.players[ind] = res.players[ind] ? res.players[ind] + val : val; 26 | 27 | if (!res.links[server.countryName]) res.links[server.countryName] = {}; 28 | res.links[server.countryName][ind] = true; 29 | }); 30 | }); 31 | 32 | return Promise.resolve(res); 33 | }); 34 | 35 | app.get('/api/server-countries', (req, res) => { 36 | cache.get('server-countries') 37 | .then((list) => { res.send(list); }) 38 | .catch((err) => { res.status(500).send({ error: err }); }); 39 | }); 40 | -------------------------------------------------------------------------------- /migrations/20180214041134_update_players_schema_2.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.raw(`Update players SET 4 | instastats = json_build_array( 5 | instastats::json->0, 6 | instastats::json->1, 7 | instastats::json->2, 8 | instastats::json->3, 9 | (instastats::json->5)::TEXT::NUMERIC * (instastats::json->0)::TEXT::NUMERIC 10 | ), efficstats = json_build_array( 11 | efficstats::jsonb->0, 12 | efficstats::json->1, 13 | efficstats::json->2, 14 | efficstats::json->3, 15 | (efficstats::json->5)::TEXT::NUMERIC * (efficstats::json->0)::TEXT::NUMERIC 16 | )`); 17 | }; 18 | 19 | exports.down = function(knex, Promise) { 20 | return knex.raw(`Update players SET 21 | instastats = json_build_array( 22 | instastats::json->0, 23 | instastats::json->1, 24 | instastats::json->2, 25 | instastats::json->3, 26 | (instastats::json->0)::TEXT::NUMERIC / (instastats::jsonb->2)::TEXT::NUMERIC, 27 | (instastats::json->5)::TEXT::NUMERIC / (instastats::jsonb->0)::TEXT::NUMERIC 28 | ), efficstats = json_build_array( 29 | efficstats::json->0, 30 | efficstats::json->1, 31 | efficstats::json->2, 32 | efficstats::json->3, 33 | (efficstats::json->0)::TEXT::NUMERIC / (efficstats::jsonb->2)::TEXT::NUMERIC, 34 | (efficstats::json->5)::TEXT::NUMERIC / (efficstats::json->0)::TEXT::NUMERIC 35 | )`); 36 | }; 37 | -------------------------------------------------------------------------------- /website/views/metrics.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = "home"; 5 | - title = "Metrics"; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li.current= title 11 | .medium-12.columns.end 12 | label.big Number of servers: #{Object.keys(metrics).length} 13 | br 14 | label.big Server poll stats: 15 | table 16 | thead 17 | tr 18 | td(width="200px") Server 19 | td(width="200px", style="text-align: right;") Total Polls 20 | td(width="200px", style="text-align: right;") Total Replies 21 | td(width="200px", style="text-align: right;") Loss 22 | tbody 23 | for metric, key in metrics 24 | tr 25 | td #{key} 26 | td(style="text-align: right;") #{metric.polls || 0} 27 | td(style="text-align: right;") #{metric.replies || 0} 28 | if metric.polls > 0 29 | td(style="text-align: right;") #{Math.floor(100 - 100 * ((metric.replies || 0) / metric.polls))}% 30 | else 31 | td(style="text-align: right;") 100% 32 | -------------------------------------------------------------------------------- /src/util/metrics.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Promise from 'bluebird'; 3 | 4 | import redis from './redis'; 5 | 6 | /** 7 | * Server has been polled. 8 | * @param {string} host - Server's IP address. 9 | * @param {number} port - Server's port number. 10 | */ 11 | export function serverPolled(host, port) { 12 | return redis.hincrbyAsync('servers-polled', `${host}:${port}`, 1); 13 | } 14 | 15 | /** 16 | * Server has replied. 17 | * @param {string} host - Server's IP address. 18 | * @param {number} port - Server's port number. 19 | */ 20 | export function serverReplied(host, port) { 21 | return redis.hincrbyAsync('servers-replied', `${host}:${port}`, 1); 22 | } 23 | 24 | /** 25 | * Get all stats. 26 | * @returns {object} An object whose keys correspond to `host:port` values of servers, 27 | * and whose values are objects containing the properties `polls` and `replies`, 28 | * representing the total number of times the server was polled and the total number of 29 | * times it replied, respectively. 30 | */ 31 | export function getAllMetrics() { 32 | return Promise.join( 33 | redis.hgetallAsync('servers-polled'), redis.hgetallAsync('servers-replied'), 34 | (serversPolled, serversReplied) => _.merge( 35 | {}, 36 | _.mapValues(serversPolled, polls => ({ polls: Number(polls) })), 37 | _.mapValues(serversReplied, replies => ({ replies: Number(replies) })), 38 | ), 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /src/api/team-balance.js: -------------------------------------------------------------------------------- 1 | import dgram from 'dgram'; 2 | 3 | import { logInfo, logError } from '../util/util'; 4 | import { getBalancePort } from '../util/config'; 5 | import Packet from '../util/packet'; 6 | 7 | export default function startTeamBalanceServer() { 8 | const server = dgram.createSocket('udp4'); 9 | 10 | server.on('error', err => { 11 | logError(`server error:\n${err.stack}`); 12 | server.close(); 13 | }); 14 | 15 | server.on('message', (data, rinfo) => { 16 | const st = new Packet(data, 0); 17 | let s = st.getString(); 18 | const names = []; 19 | let mode; 20 | let map; 21 | while (s) { 22 | names.push(s); 23 | s = st.getString(); 24 | } 25 | s = st.getString(); 26 | if (s) mode = s; 27 | s = st.getString(); 28 | if (s) map = s; 29 | 30 | makeTeams(names, mode, map).then(teams => { 31 | // eslint-disable-next-line new-cap 32 | const buf = new Buffer.alloc(1024); 33 | const p = new Packet(buf); 34 | 35 | _.each(teams, team => { 36 | _.each(team, player => { 37 | p.putInt(names.indexOf(player)); 38 | }); 39 | }); 40 | 41 | server.send(buf, 0, p.offset, rinfo.port, rinfo.address); 42 | }); 43 | }); 44 | 45 | server.on('listening', () => { 46 | const address = server.address(); 47 | logInfo(`Team balance server listening on port ${address.port}`); 48 | }); 49 | 50 | server.bind(getBalancePort()); 51 | } 52 | -------------------------------------------------------------------------------- /src/util/web.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import http from 'http'; 3 | import bodyParser from 'body-parser'; 4 | 5 | import { logInfo } from '../util/util'; 6 | import { getPort } from '../util/config'; 7 | 8 | const app = express(); 9 | export default app; 10 | 11 | app.set('trust proxy', 'loopback'); 12 | 13 | app.use(bodyParser.json()); 14 | app.use(bodyParser.urlencoded({ extended: true })); 15 | 16 | if (process.env.NODE_ENV !== 'production') app.locals.pretty = true; 17 | 18 | app.use((req, res, next) => { 19 | // If using an old domain, redirect to "sauertracker.net" 20 | if ( 21 | req.get('host') === 'uk.cube2.org' || 22 | req.get('host') === 'tracker.impressivesquad.eu' 23 | ) { 24 | res.redirect(`${req.protocol}://sauertracker.net${req.originalUrl}`); 25 | return; 26 | } 27 | 28 | // Enable cross-origin on all routes 29 | res.header('Access-Control-Allow-Origin', '*'); 30 | res.header( 31 | 'Access-Control-Allow-Headers', 32 | 'Origin, X-Requested-With, Content-Type, Accept' 33 | ); 34 | 35 | // Disable caching on /api/ routes (fixes bug on Dolphin browser) 36 | if (req.path.indexOf('/api/') === 0) { 37 | res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); 38 | res.setHeader('Pragma', 'no-cache'); 39 | res.setHeader('Expires', '0'); 40 | } 41 | 42 | next(); 43 | }); 44 | 45 | app.use('/', express.static('./assets', { maxAge: 24 * 60 * 60 * 1000 })); 46 | 47 | http.createServer(app.handle.bind(app)).listen(getPort(), () => { 48 | logInfo(`Server listening on port ${getPort()}`); 49 | }); 50 | -------------------------------------------------------------------------------- /src/scripts/detect-clanwars.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/first */ 2 | require('source-map-support').install(); 3 | 4 | import _ from 'lodash'; 5 | 6 | import database from '../util/database'; 7 | import { getGameType } from '../tracker/game'; 8 | 9 | let count = 0; 10 | 11 | database.raw(` 12 | SELECT games.id, 13 | games.gamemode, 14 | games.gametype, 15 | (SELECT array_to_json(array_agg(row(scores.team, scores.score))) FROM scores WHERE scores.game = games.id) teams, 16 | (SELECT array_to_json(array_agg(row(stats.name, stats.team, stats.frags)))app FROM stats WHERE stats.game = games.id AND stats.state != 5) players 17 | 18 | FROM games 19 | 20 | WHERE games.gametype = 'mix' OR 21 | games.gametype = 'clanwar' 22 | `) 23 | // eslint-disable-next-line array-callback-return,consistent-return 24 | .then(result => result.rows).map((row) => { 25 | const players = _.map(row.players, player => ({ 26 | name: player.f1, 27 | team: player.f2, 28 | frags: player.f3, 29 | })); 30 | const teams = {}; 31 | _.each(row.teams, (team) => { 32 | teams[team.f1] = team.f2; 33 | }); 34 | const g = { 35 | masterMode: 'locked', teams, players, gameMode: row.gamemode, 36 | }; 37 | const gameType = getGameType(g); 38 | database.raw(); 39 | if (gameType[0] !== row.gametype) { 40 | count++; 41 | return database('games').where('id', row.id).update({ gametype: gameType[0], meta: JSON.stringify(gameType[1]) }).then(); 42 | } 43 | }).then(() => { 44 | console.log(`Updated ${count} games`); // eslint-disable-line no-console 45 | process.exit(); 46 | }); 47 | -------------------------------------------------------------------------------- /migrations/20161202143509_update_mode_names.js: -------------------------------------------------------------------------------- 1 | 2 | exports.up = function(knex, Promise) { 3 | return knex.raw(` 4 | UPDATE games SET 5 | gamemode = c.new_name 6 | FROM (values 7 | ('coop', 'coop_edit'), 8 | ('insta', 'instagib'), 9 | ('instateam', 'insta_team'), 10 | ('effic', 'efficiency'), 11 | ('efficteam', 'effic_team'), 12 | ('tac', 'tactics'), 13 | ('tacteam', 'tac_team'), 14 | ('rcapture', 'regen_capture'), 15 | ('ictf', 'insta_ctf'), 16 | ('iprotect', 'insta_protect'), 17 | ('ihold', 'insta_hold'), 18 | ('ectf', 'effic_ctf'), 19 | ('eprotect', 'effic_protect'), 20 | ('ehold', 'effic_hold'), 21 | ('icollect', 'insta_collect'), 22 | ('ecollect', 'effic_collect') 23 | ) AS c(old_name, new_name) 24 | WHERE c.old_name = games.gamemode 25 | `); 26 | }; 27 | 28 | exports.down = function(knex, Promise) { 29 | return knex.raw(` 30 | UPDATE games SET 31 | gamemode = c.new_name 32 | FROM (values 33 | ('coop_edit', 'coop'), 34 | ('instagib', 'insta'), 35 | ('insta_team', 'instateam'), 36 | ('efficiency', 'effic'), 37 | ('effic_team', 'efficteam'), 38 | ('tactics', 'tac'), 39 | ('tac_team', 'tacteam'), 40 | ('regen_capture', 'rcapture'), 41 | ('insta_ctf', 'ictf'), 42 | ('insta_protect', 'iprotect'), 43 | ('insta_hold', 'ihold'), 44 | ('effic_ctf', 'ectf'), 45 | ('effic_protect', 'eprotect'), 46 | ('effic_hold', 'ehold'), 47 | ('insta_collect', 'icollect'), 48 | ('effic_collect', 'ecollect') 49 | ) AS c(old_name, new_name) 50 | WHERE c.old_name = games.gamemode 51 | `); 52 | }; 53 | -------------------------------------------------------------------------------- /website/js/players.js: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress'; 2 | import _ from 'lodash'; 3 | 4 | const $ = window.jQuery; 5 | 6 | import searchResultsTemplate from 'pug-loader!../views/_partials/player-search-results.pug'; 7 | 8 | const originalURL = 9 | window.location.pathname + window.location.search + window.location.hash; 10 | 11 | function loadPage(url, name) { 12 | NProgress.start(); 13 | $.get(`/api${url}`) 14 | .success(result => { 15 | $('#search-result-container').html( 16 | searchResultsTemplate({ results: result.results, _ }) 17 | ); 18 | }) 19 | .fail(() => { 20 | $('#search-result-container').html('Error loading search results.'); 21 | }) 22 | .always(() => { 23 | $('#name').val(name); 24 | NProgress.done(); 25 | }); 26 | } 27 | 28 | $('#search-form').on('submit', function(event) { 29 | event.preventDefault(); 30 | const url = `/players/find?${$(this).serialize()}`; 31 | const name = $('#name').val(); 32 | loadPage(url, name); 33 | window.history.pushState({ url, name }, window.title, url); 34 | }); 35 | 36 | $(window).bind('popstate', event => { 37 | const { state } = event.originalEvent; 38 | if (!state) { 39 | if (originalURL === '/players') window.location.reload(); 40 | else loadPage(originalURL); 41 | } else loadPage(state.url, state.name); 42 | }); 43 | 44 | window.selectCategory = function(category) { 45 | $('.category-body').hide(); 46 | $(`#top-${category}`).show(); 47 | $('.category-title').removeClass('inverted'); 48 | $(`#ct-${category}`).addClass('inverted'); 49 | }; 50 | 51 | window.selectCategory('monthly'); 52 | -------------------------------------------------------------------------------- /website/views/server.pug: -------------------------------------------------------------------------------- 1 | extends ./_layout.pug 2 | 3 | block vars 4 | - section = "servers"; 5 | - title = server.description; 6 | 7 | block content 8 | .row.main-container 9 | ul.breadcrumbs 10 | li Servers 11 | li.current #{server.description} 12 | .medium-12.columns 13 | #game 14 | include ./_partials/game.pug 15 | if bannerURL 16 | br 17 | a(href="/banners?type=server&host="+server.host+"&port="+server.port) 18 | img#banner(src=bannerURL+"server?theme=default&host="+server.host+"&port="+server.port) 19 | if !server.info.banned && !server.zombie 20 | .row.columns.client-side(style="margin-top: 1em") 21 | label.big Server activity for today (avg # of players, time is in UTC): 22 | div(style="width: 100%; margin-right: 50px;") 23 | canvas#server-activity-day(style="width: 100%; height: 300px;") 24 | .row.columns.client-side 25 | label.big Server activity for the last 15 days (# of games): 26 | div(style="width: 100%; margin-right: 50px;") 27 | canvas#server-activity-month(style="width: 100%; height: 300px;") 28 | 29 | .reveal#connect-info(data-reveal) 30 | | Copy the following line, paste it in the game, and press Enter to connect to the server: 31 | br 32 | br 33 | input#connect-command(type="text", value="/connect", onfocus="$(this).select()") 34 | 35 | block scripts 36 | script(src="/js/server.js") 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SauerTracker", 3 | "version": "4.0.0", 4 | "description": "Server and stats tracker for Cube 2: Sauerbraten.", 5 | "main": "index.js", 6 | "repository": "https://github.com/AngrySnout/SauerTracker.git", 7 | "author": "AngrySnout", 8 | "license": "MIT", 9 | "scripts": { 10 | "build": "webpack-cli --mode production", 11 | "buildDev": "webpack-cli --mode development", 12 | "migrate": "knex migrate:latest", 13 | "start": "node dist/tracker.js", 14 | "detectClanwars": "node dist/detectClanwars.js", 15 | "recalculateElo": "node dist/recalculateElo.js" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.8.4", 19 | "@babel/node": "^7.8.4", 20 | "@babel/preset-env": "^7.8.4", 21 | "css-loader": "^3.4.2", 22 | "imports-loader": "^0.8.0", 23 | "node-sass": "^4.13.1", 24 | "pug-loader": "^2.4.0", 25 | "sass-loader": "^8.0.2", 26 | "style-loader": "^1.1.3", 27 | "webpack": "^4.41.5", 28 | "webpack-cli": "^3.3.10", 29 | "webpack-glob-entries": "^1.0.1" 30 | }, 31 | "dependencies": { 32 | "bluebird": "^3.7.2", 33 | "body-parser": "^1.19.0", 34 | "chart.js": "^2.9.3", 35 | "codemirror": "^5.51.0", 36 | "express": "^4.17.1", 37 | "font-awesome": "^4.7.0", 38 | "fuzzaldrin": "^2.1.0", 39 | "handlebars": "^4.7.3", 40 | "i18n-iso-countries": "^4.3.1", 41 | "ip2location-nodejs": "^8.3.0", 42 | "knex": "^0.21.1", 43 | "lodash": "^4.17.15", 44 | "moment": "^2.24.0", 45 | "nprogress": "^0.2.0", 46 | "pg": "^8.0.3", 47 | "pug": "^2.0.4", 48 | "pug-runtime": "^2.0.5", 49 | "redis": "^3.0.2", 50 | "winston": "^3.2.1", 51 | "winston-daily-rotate-file": "^4.4.2" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /website/views/_partials/player-search-results.pug: -------------------------------------------------------------------------------- 1 | if results.length 2 | table.scroll#search-results(width="100%") 3 | thead 4 | tr 5 | td(width="19%") Name 6 | td(width="9%") Frags 7 | td(width="9%") Flags 8 | td(width="9%") Deaths 9 | td(width="9%") TKs 10 | td(width="9%") K/D 11 | td(width="9%") Accuracy 12 | td(width="9%") Elo 13 | td(width="18%") Country 14 | tbody 15 | for player in results 16 | tr.unclickable 17 | td 18 | a(href=("/player/"+encodeURIComponent(player.name)))= player.name 19 | if player.online 20 | | 21 | span.label.success online 22 | td= player.frags 23 | td= player.flags 24 | td= player.deaths 25 | td= player.tks 26 | td= player.kpd 27 | td= _.padStart(parseInt(player.acc).toString(), 2, "0")+"%" 28 | td= player.elo 29 | td 30 | if player.country 31 | img.flag(src=("/images/flags/"+player.country+".png")) 32 | | 33 | a.no-color(href="/players/find?country="+player.country)= player.countryName 34 | else 35 | | Unknown 36 | 37 | if (results.length == 200) 38 | | Results are too big to show. You should narrow down your search query. 39 | 40 | else 41 | | No results. 42 | -------------------------------------------------------------------------------- /src/api/v2/clans.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable guard-for-in,no-restricted-syntax */ 2 | import _ from 'lodash'; 3 | import Promise from 'bluebird'; 4 | 5 | import vars from '../../../vars.json'; 6 | 7 | import app from '../../util/web'; 8 | import cache from '../../util/cache'; 9 | import { logError, round2 } from '../../util/util'; 10 | import redis from '../../util/redis'; 11 | 12 | cache.set('clans-v2', 10 * 60 * 1000, () => Promise.join( 13 | redis.hgetallAsync('clan-games'), redis.hgetallAsync('clan-wins'), redis.hgetallAsync('clan-losses'), 14 | (games, wins, losses) => { 15 | games = _.mapValues(games, Number); 16 | wins = _.mapValues(wins, Number); 17 | losses = _.mapValues(losses, Number); 18 | const clns = _.orderBy(_.map(vars.clans, (clan) => { 19 | if (!wins[clan.tag]) wins[clan.tag] = 0; 20 | if (!losses[clan.tag]) losses[clan.tag] = 0; 21 | const draws = ((games[clan.tag] || 0) - ((wins[clan.tag] || 0) + (losses[clan.tag] || 0))); 22 | const rate = (games[clan.tag] ? (wins[clan.tag] + draws / 2) / games[clan.tag] : 0); 23 | return { 24 | tag: clan.tag, 25 | title: clan.title, 26 | website: clan.website, 27 | wins: wins[clan.tag], 28 | losses: losses[clan.tag], 29 | ties: draws, 30 | rate: round2(rate), 31 | points: round2((wins[clan.tag] + draws / 2) * rate), 32 | }; 33 | }), 'points', 'desc'); 34 | let rank = 1; 35 | _.each(clns, (clan) => { 36 | clan.rank = rank++; 37 | }); 38 | return clns; 39 | }, 40 | )); 41 | 42 | export function getClans() { 43 | return cache.get('clans-v2'); 44 | } 45 | 46 | app.get('/api/v2/clans', (req, res) => { 47 | getClans().then((clans) => { 48 | res.send({ clans }); 49 | }).catch((err) => { 50 | logError(err); 51 | res.status(500).send({ error: err.message }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/util/cache.js: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | 3 | import redis from './redis'; 4 | import { logError } from './util'; 5 | 6 | class CacheManager { 7 | constructor() { 8 | this.entries = {}; 9 | } 10 | 11 | /** 12 | * Add a cache function. 13 | * @param {string} id - A unique name for the function. 14 | * @param {string} maxage - Approximately, how often, in milliseconds, 15 | * should the stored value be purged. 16 | * @param {function} func - A function that returns a promise which resolves 17 | * to the value that should be stored. 18 | */ 19 | set(id, maxage, func) { 20 | this.entries[id] = { maxage: maxage / 1000, func }; 21 | } 22 | 23 | /** 24 | * Get a value from cache. If the value stored has expired the 25 | * generator function will be called again. 26 | * @param id - {string} The name of the function to call. 27 | * @returns {Promise} Rejects if the function is not set. 28 | * Resolves with the value returned by the generator function. 29 | */ 30 | get(id) { 31 | const self = this; 32 | return new Promise((resolve, reject) => { 33 | if (!self.entries[id]) { 34 | // eslint-disable-next-line prefer-promise-reject-errors 35 | reject('Cache entry not set'); 36 | return; 37 | } 38 | const key = `cache-${id}`; 39 | redis.getAsync(key) 40 | .then((reply) => { 41 | if (!reply) { 42 | self.entries[id].func().then((res) => { 43 | redis.setAsync(key, JSON.stringify(res), 'EX', self.entries[id].maxage).then(() => { 44 | resolve(res); 45 | }); 46 | }).catch((err) => { 47 | logError(err); 48 | resolve(); 49 | }); 50 | } else resolve(JSON.parse(reply.toString())); 51 | }); 52 | }); 53 | } 54 | } 55 | 56 | const cache = new CacheManager(); 57 | export default cache; 58 | -------------------------------------------------------------------------------- /website/styles/_nprogress.scss: -------------------------------------------------------------------------------- 1 | $progress-bar-color: #dd7c22; 2 | 3 | /* Make clicks pass-through */ 4 | #nprogress { 5 | pointer-events: none; 6 | } 7 | 8 | #nprogress .bar { 9 | background: $progress-bar-color; 10 | 11 | position: fixed; 12 | z-index: 1031; 13 | top: 0; 14 | left: 0; 15 | 16 | width: 100%; 17 | height: 2px; 18 | } 19 | 20 | /* Fancy blur effect */ 21 | #nprogress .peg { 22 | display: block; 23 | position: absolute; 24 | right: 0px; 25 | width: 100px; 26 | height: 100%; 27 | box-shadow: 0 0 10px $progress-bar-color, 0 0 5px $progress-bar-color; 28 | opacity: 1.0; 29 | 30 | -webkit-transform: rotate(3deg) translate(0px, -4px); 31 | -ms-transform: rotate(3deg) translate(0px, -4px); 32 | transform: rotate(3deg) translate(0px, -4px); 33 | } 34 | 35 | /* Remove these to get rid of the spinner */ 36 | #nprogress .spinner { 37 | display: block; 38 | position: fixed; 39 | z-index: 1031; 40 | top: 15px; 41 | right: 15px; 42 | } 43 | 44 | #nprogress .spinner-icon { 45 | width: 18px; 46 | height: 18px; 47 | box-sizing: border-box; 48 | 49 | border: solid 2px transparent; 50 | border-top-color: $progress-bar-color; 51 | border-left-color: $progress-bar-color; 52 | border-radius: 50%; 53 | 54 | -webkit-animation: nprogress-spinner 400ms linear infinite; 55 | animation: nprogress-spinner 400ms linear infinite; 56 | } 57 | 58 | .nprogress-custom-parent { 59 | overflow: hidden; 60 | position: relative; 61 | } 62 | 63 | .nprogress-custom-parent #nprogress .spinner, 64 | .nprogress-custom-parent #nprogress .bar { 65 | position: absolute; 66 | } 67 | 68 | @-webkit-keyframes nprogress-spinner { 69 | 0% { -webkit-transform: rotate(0deg); } 70 | 100% { -webkit-transform: rotate(360deg); } 71 | } 72 | @keyframes nprogress-spinner { 73 | 0% { transform: rotate(0deg); } 74 | 100% { transform: rotate(360deg); } 75 | } 76 | -------------------------------------------------------------------------------- /src/api/v1/clan.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Promise from 'bluebird'; 3 | 4 | import vars from '../../../vars.json'; 5 | 6 | import app from '../../util/web'; 7 | import cache from '../../util/cache'; 8 | import { logError, ObjectNotFoundError, escapePostgresLike } from '../../util/util'; 9 | import database from '../../util/database'; 10 | 11 | function getLatestGames(clan) { 12 | return database('games').where('meta', 'like', `%${escapePostgresLike(clan.replace(/"/g, '\\"'))}%`).where({ gametype: 'clanwar' }).orderBy('id', 'desc') 13 | .limit(10) 14 | .then((rows) => { 15 | _.each(rows, (game) => { 16 | if (game.meta) { 17 | try { 18 | game.meta = JSON.parse(game.meta); 19 | } catch (e) { 20 | game.meta = []; 21 | } 22 | if (game.meta[1] === game.meta[3]) game.draw = true; 23 | } else game.meta = []; 24 | }); 25 | 26 | return rows; 27 | }); 28 | } 29 | 30 | function getLatestMembers(clan) { 31 | return database('spy').where('name', 'ilike', `%${escapePostgresLike(clan)}%`).max('lastseen as lastseen').select('name') 32 | .groupBy('name') 33 | .orderBy('lastseen', 'desc') 34 | .limit(9); 35 | } 36 | 37 | export function getClan(name) { 38 | return Promise.all([cache.get('clans'), getLatestGames(name), getLatestMembers(name)]) 39 | .spread((clans, latestGames, latestMembers) => { 40 | const clan = _.find(clans, { name }); 41 | if (!clan) throw new ObjectNotFoundError(); 42 | 43 | const info = _.find(vars.clans, { tag: name }); 44 | return { 45 | clan, info, games: latestGames, members: latestMembers, 46 | }; 47 | }); 48 | } 49 | 50 | app.get('/api/clan/:name', (req, res) => { 51 | getClan(req.params.name) 52 | .then((result) => { res.send(result); }) 53 | .catch(ObjectNotFoundError, () => { res.status(404).send({ error: 'Clan not found.' }); }) 54 | .catch((err) => { 55 | logError(err); 56 | res.status(500).send({ error: err.message }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /src/scripts/recalculate-elo.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/first */ 2 | require('source-map-support').install(); 3 | 4 | import Promise from 'bluebird'; 5 | import _ from 'lodash'; 6 | 7 | import database from '../util/database'; 8 | import { calcEloChange } from '../tracker/game'; 9 | import { getBaseElo } from '../util/config'; 10 | 11 | database('players') 12 | .update({ elo: getBaseElo() }) 13 | .then(() => { 14 | database('games') 15 | .where({ gametype: 'duel' }) 16 | .orderBy('id', 'asc') 17 | .then(rows => { 18 | const newElos = {}; 19 | _.each(rows, row => { 20 | try { 21 | const meta = JSON.parse(row.meta); 22 | 23 | if (!(meta[0] in newElos)) newElos[meta[0]] = getBaseElo(); 24 | if (!(meta[2] in newElos)) newElos[meta[2]] = getBaseElo(); 25 | 26 | const elod1 = calcEloChange( 27 | newElos[meta[0]], 28 | newElos[meta[2]], 29 | meta[1], 30 | meta[3] 31 | ); 32 | const elod2 = calcEloChange( 33 | newElos[meta[2]], 34 | newElos[meta[0]], 35 | meta[3], 36 | meta[1] 37 | ); 38 | 39 | newElos[meta[0]] += elod1; 40 | newElos[meta[2]] += elod2; 41 | } catch (e) { 42 | console.log(`Error parsing JSON: ${row.meta}`); 43 | } // eslint-disable-line no-console 44 | }); 45 | return newElos; 46 | }) 47 | .then(newElos => 48 | Promise.all( 49 | _.keys(newElos).map(player => 50 | database('players') 51 | .where({ name: player }) 52 | .update({ elo: newElos[player] }) 53 | .then() 54 | .catch(() => console.log(`Error updating player Elo: ${player}`)) 55 | ) 56 | ) 57 | ) // eslint-disable-line no-console 58 | .finally(process.exit); 59 | }); 60 | -------------------------------------------------------------------------------- /website/js/main.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment'; 2 | import _ from 'lodash'; 3 | 4 | const $ = window.jQuery; 5 | 6 | // import '../styles/styles.scss'; 7 | 8 | window.dateReflow = function() { 9 | const now = moment(); 10 | $('.date').each(function() { 11 | const cd = moment( 12 | `${$(this) 13 | .text() 14 | .replace(/[TZ]/g, ' ') 15 | .trim()}+0000` 16 | ); 17 | $(this).attr('title', cd.format('dddd, MMMM Do YYYY, HH:mm:ss')); 18 | if (cd.diff(now, 'hours') >= -22) $(this).text(cd.fromNow()); 19 | else if (cd.diff(now, 'days') >= -7) 20 | $(this).text(cd.fromNow() + cd.format(', HH:mm')); 21 | else if (!cd.isSame(now, 'year')) 22 | $(this).text(cd.format('MMMM Do YYYY, HH:mm')); 23 | else if (cd.diff(now, 'days') < -7) 24 | $(this).text(cd.format('MMMM Do, HH:mm')); 25 | $(this).addClass('date-active'); 26 | $(this).removeClass('date'); 27 | }); 28 | }; 29 | 30 | window.disableDefault = function() { 31 | $('.disable-default').addClass('disable-default-active'); 32 | $('.disable-default-active').click(e => { 33 | e.preventDefault(); 34 | }); 35 | }; 36 | 37 | window.showConnect = function(host, port) { 38 | $('#connect-command').val(`/connect ${host} ${port}`); 39 | $('#connect-info').foundation('open'); 40 | $('#connect-command').focus(); 41 | }; 42 | 43 | window.tryLoadBackground = function(name) { 44 | const bg = new Image(); 45 | bg.onload = function() { 46 | $('body').css( 47 | 'background', 48 | `url(/images/mapshots/${name}.jpg) no-repeat center center fixed` 49 | ); 50 | $('body').css('background-size', 'cover'); 51 | }; 52 | bg.src = `/images/mapshots/${name}.jpg`; 53 | }; 54 | 55 | $(window.document).ready(() => { 56 | $('.client-side').css('display', 'inline-block'); 57 | $(document).foundation(); 58 | window.dateReflow(); 59 | window.disableDefault(); 60 | }); 61 | 62 | let pollVisible = false; 63 | 64 | window.togglePoll = function() { 65 | pollVisible = !pollVisible; 66 | 67 | if (pollVisible) { 68 | $('.slidebar').animate({ left: '0px' }, 400, 'linear'); 69 | } else { 70 | $('.slidebar').animate({ left: '-490px' }, 400, 'linear'); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/tracker/master.js: -------------------------------------------------------------------------------- 1 | import net from 'net'; 2 | import Promise from 'bluebird'; 3 | import _ from 'lodash'; 4 | 5 | import redis from '../util/redis'; 6 | import { logInfo, logError } from '../util/util'; 7 | import { getMasterPort, getMasterHost } from '../util/config'; 8 | 9 | function pollMasterServer() { 10 | return new Promise((resolve, reject) => { 11 | let agg = ''; 12 | const socket = net.connect(getMasterPort(), getMasterHost(), () => { 13 | socket.write('list\n'); 14 | }); 15 | socket.on('data', data => { 16 | agg += data.toString(); 17 | }); 18 | socket.on('end', () => { 19 | if (!agg) reject('Masterserver connection failed.'); 20 | resolve(agg); 21 | }); 22 | socket.on('error', err => { 23 | reject(["Can't poll masterserver:", err]); 24 | }); 25 | }); 26 | } 27 | 28 | /** 29 | * Poll the master server. 30 | * @returns {Promise} Resolves with an array containing objects of the form 31 | * `{ host: "x.x.x.x", port: 12345 }`. 32 | */ 33 | export function getServerList() { 34 | return pollMasterServer().then(result => { 35 | const servers = []; 36 | _.each(result.split('\n'), line => { 37 | const ts = line.split(' '); 38 | if (ts.length === 3 && ts[0] === 'addserver') 39 | servers.push({ host: ts[1], port: parseInt(ts[2], 10) }); 40 | }); 41 | return servers; 42 | }); 43 | } 44 | 45 | /** 46 | * Get the server list from the master server and save it in cache. 47 | */ 48 | export function updateServerList() { 49 | return redis.getAsync('last-master-update').then(lastUpdate => { 50 | if (lastUpdate && Date.now() - lastUpdate < 600000) return; 51 | getServerList() 52 | .then(results => { 53 | logInfo( 54 | `Updated server list from master server (${results.length} servers)` 55 | ); 56 | return Promise.all([ 57 | redis.setAsync('servers', JSON.stringify(results)), 58 | redis.setAsync('last-master-update', Date.now()), 59 | ]); 60 | }) 61 | .catch(err => { 62 | logError(err); 63 | return err; 64 | }); 65 | }); 66 | } 67 | 68 | /** 69 | * Run updateServerList every interval milliseconds. 70 | */ 71 | export function start() { 72 | setInterval(updateServerList, 30000); 73 | updateServerList(); 74 | } 75 | -------------------------------------------------------------------------------- /src/api/v2/players.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import app from '../../util/web'; 4 | import { round2, escapePostgresLike } from '../../util/util'; 5 | import database from '../../util/database'; 6 | import playerManager from '../../tracker/player-manager'; 7 | import { getCountryName } from '../../util/country'; 8 | 9 | export function findPlayers(name, country) { 10 | if (typeof name === 'undefined') name = ''; 11 | const query = database('players').where('name', 'ilike', `%${escapePostgresLike(name)}%`); 12 | if (country) { 13 | query.where(function () { 14 | if (country === '__') this.where({ country: '' }).orWhereNull('country'); 15 | else this.where({ country }); 16 | }); 17 | } 18 | return query.orderBy('frags', 'desc').limit(200).then((rows) => { 19 | _.each(rows, (row) => { 20 | row.online = playerManager.isOnline(row.name); 21 | row.country = row.country || ''; 22 | row.countryName = getCountryName(row.country); 23 | row.kpd = round2(row.frags / row.deaths); 24 | row.acc = round2(row.accFrags / row.frags); 25 | delete row.accFrags; 26 | 27 | row.instaStats = { 28 | frags: 0, flags: 0, deaths: 0, tks: 0, acc: 0, 29 | }; 30 | try { 31 | const stats = JSON.parse(row.instastats); 32 | const [frags, flags, deaths, tks, accFrags] = stats; 33 | row.instaStats = { 34 | frags, 35 | flags, 36 | deaths, 37 | tks, 38 | kpd: round2(frags / deaths) || 0, 39 | acc: round2(accFrags / frags) || 0, 40 | }; 41 | } catch (e) {} // eslint-disable-line no-empty 42 | delete row.instastats; 43 | 44 | row.efficStats = { 45 | frags: 0, flags: 0, deaths: 0, tks: 0, acc: 0, 46 | }; 47 | try { 48 | const stats = JSON.parse(row.efficstats); 49 | const [frags, flags, deaths, tks, accFrags] = stats; 50 | row.efficStats = { 51 | frags, 52 | flags, 53 | deaths, 54 | tks, 55 | kpd: round2(frags / deaths) || 0, 56 | acc: round2(accFrags / frags) || 0, 57 | }; 58 | } catch (e) {} // eslint-disable-line no-empty 59 | delete row.efficstats; 60 | }); 61 | return rows; 62 | }); 63 | } 64 | 65 | app.get('/api/v2/players/find', (req, res) => { 66 | findPlayers(req.query.name, req.query.country) 67 | .then((results) => { res.send(results); }) 68 | .catch((err) => { res.status(500).send({ error: err.message }); }); 69 | }); 70 | -------------------------------------------------------------------------------- /src/tracker/player-manager.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Promise from 'bluebird'; 3 | 4 | import { logInfo, logError } from '../util/util'; 5 | import database from '../util/database'; 6 | import Player from './player'; 7 | import { saveSpy } from './spy'; 8 | 9 | class PlayerManager { 10 | constructor() { 11 | this.players = {}; 12 | this.oldPlayers = {}; 13 | this.bans = {}; 14 | this.banNames = {}; 15 | } 16 | 17 | updatePlayer(gameMode, newState, oldState) { 18 | const { name } = newState; 19 | if (this.banNames[name] || this.bans[newState.ip]) return; 20 | if (!this.players[name]) this.players[name] = new Player(name); 21 | this.players[name].updateState(gameMode, newState, oldState); 22 | } 23 | 24 | flushPlayers() { 25 | const self = this; 26 | return database('players') 27 | .whereIn('name', _.map(self.players, 'name')) 28 | .then(rows => { 29 | rows = _.keyBy(rows, 'name'); 30 | const players = _.values(self.players); 31 | const numPlayers = players.length; 32 | return database 33 | .transaction(trx => 34 | Promise.all( 35 | _.map(players, player => player.saveStats(rows[player.name], trx)) 36 | ) 37 | ) 38 | .then(() => { 39 | self.oldPlayers = self.players; 40 | self.players = {}; 41 | return numPlayers; 42 | }); 43 | }) 44 | .then(numPlayers => { 45 | logInfo(`Players flushed, ${numPlayers} players updated`); 46 | }) 47 | .then(saveSpy) 48 | .catch(error => { 49 | logError(`${error}`); 50 | }); 51 | } 52 | 53 | isOnline(name) { 54 | return !!(this.players[name] || this.oldPlayers[name]); 55 | } 56 | 57 | start() { 58 | const self = this; 59 | database 60 | .select() 61 | .table('bans') 62 | .then(bans => { 63 | _.each(bans, ban => { 64 | if (ban.ip) self.bans[ban.ip] = true; 65 | if (ban.name) self.banNames[ban.name] = true; 66 | }); 67 | }); 68 | 69 | setInterval(() => { 70 | this.flushPlayers(); 71 | }, 60000); 72 | 73 | process.on('SIGINT', () => { 74 | self.flushPlayers().finally(process.exit); 75 | }); 76 | } 77 | } 78 | 79 | const playerManager = new PlayerManager(); 80 | export default playerManager; 81 | --------------------------------------------------------------------------------