From dfc4e20b8e9ca57340e24143539498fb82527697 Mon Sep 17 00:00:00 2001 From: randommonk Date: Thu, 4 Jan 2018 22:52:54 +0000 Subject: Bumped version to 4.3. Added jpgraph stats developed by killerEye --- html/includes/config.php | 61 +- html/includes/css/themes/tooltipster-light.css | 12 + html/includes/css/themes/tooltipster-noir.css | 12 + html/includes/css/themes/tooltipster-punk.css | 12 + html/includes/css/themes/tooltipster-shadow.css | 12 + html/includes/css/tooltipster.css | 283 + html/includes/domstats.php | 719 + html/includes/encoding.php | 304 + html/includes/footer.php | 2 +- html/includes/ftptimestamp.php | 2 +- html/includes/header.php | 15 + html/includes/js/adapters/standalone-framework.js | 18 + .../js/adapters/standalone-framework.src.js | 603 + html/includes/js/clickrows.js | 8 + html/includes/js/clocks.js | 561 + html/includes/js/highcharts-3d.js | 45 + html/includes/js/highcharts-3d.src.js | 1383 ++ html/includes/js/highcharts-all.js | 471 + html/includes/js/highcharts-functions.js | 1 + html/includes/js/highcharts-more.js | 53 + html/includes/js/highcharts-more.src.js | 2575 +++ html/includes/js/highcharts.js | 308 + html/includes/js/highcharts.src.js | 17737 +++++++++++++++++++ html/includes/js/jquery-1.11.1.min.js | 4 + html/includes/js/jquery.tooltip.js | 119 + html/includes/js/jquery.tooltipster.js | 1327 ++ html/includes/js/jquery.tooltipster.min.js | 1 + html/includes/js/modules/canvas-tools.js | 133 + html/includes/js/modules/canvas-tools.src.js | 3113 ++++ html/includes/js/modules/data.js | 24 + html/includes/js/modules/data.src.js | 1025 ++ html/includes/js/modules/drilldown.js | 15 + html/includes/js/modules/drilldown.src.js | 606 + html/includes/js/modules/exporting.js | 23 + html/includes/js/modules/exporting.src.js | 719 + html/includes/js/modules/funnel.js | 13 + html/includes/js/modules/funnel.src.js | 310 + html/includes/js/modules/heatmap.js | 23 + html/includes/js/modules/heatmap.src.js | 687 + html/includes/js/modules/multicolor_series.js | 567 + html/includes/js/modules/no-data-to-display.js | 12 + html/includes/js/modules/no-data-to-display.src.js | 130 + html/includes/js/modules/solid-gauge.js | 13 + html/includes/js/modules/solid-gauge.src.js | 234 + html/includes/js/themes/dark-blue.js | 254 + html/includes/renderer-ctf.php | 264 + html/includes/renderer-dm.php | 252 + html/includes/renderer-dom.php | 396 + html/includes/renderer-general-import.php | 168 + html/includes/renderer-general-output.php | 195 + html/includes/teamstats.php | 12 +- 51 files changed, 35827 insertions(+), 9 deletions(-) create mode 100644 html/includes/css/themes/tooltipster-light.css create mode 100644 html/includes/css/themes/tooltipster-noir.css create mode 100644 html/includes/css/themes/tooltipster-punk.css create mode 100644 html/includes/css/themes/tooltipster-shadow.css create mode 100644 html/includes/css/tooltipster.css create mode 100644 html/includes/domstats.php create mode 100644 html/includes/encoding.php create mode 100644 html/includes/js/adapters/standalone-framework.js create mode 100644 html/includes/js/adapters/standalone-framework.src.js create mode 100644 html/includes/js/clickrows.js create mode 100644 html/includes/js/clocks.js create mode 100644 html/includes/js/highcharts-3d.js create mode 100644 html/includes/js/highcharts-3d.src.js create mode 100644 html/includes/js/highcharts-all.js create mode 100644 html/includes/js/highcharts-functions.js create mode 100644 html/includes/js/highcharts-more.js create mode 100644 html/includes/js/highcharts-more.src.js create mode 100644 html/includes/js/highcharts.js create mode 100644 html/includes/js/highcharts.src.js create mode 100644 html/includes/js/jquery-1.11.1.min.js create mode 100644 html/includes/js/jquery.tooltip.js create mode 100644 html/includes/js/jquery.tooltipster.js create mode 100644 html/includes/js/jquery.tooltipster.min.js create mode 100644 html/includes/js/modules/canvas-tools.js create mode 100644 html/includes/js/modules/canvas-tools.src.js create mode 100644 html/includes/js/modules/data.js create mode 100644 html/includes/js/modules/data.src.js create mode 100644 html/includes/js/modules/drilldown.js create mode 100644 html/includes/js/modules/drilldown.src.js create mode 100644 html/includes/js/modules/exporting.js create mode 100644 html/includes/js/modules/exporting.src.js create mode 100644 html/includes/js/modules/funnel.js create mode 100644 html/includes/js/modules/funnel.src.js create mode 100644 html/includes/js/modules/heatmap.js create mode 100644 html/includes/js/modules/heatmap.src.js create mode 100644 html/includes/js/modules/multicolor_series.js create mode 100644 html/includes/js/modules/no-data-to-display.js create mode 100644 html/includes/js/modules/no-data-to-display.src.js create mode 100644 html/includes/js/modules/solid-gauge.js create mode 100644 html/includes/js/modules/solid-gauge.src.js create mode 100644 html/includes/js/themes/dark-blue.js create mode 100644 html/includes/renderer-ctf.php create mode 100644 html/includes/renderer-dm.php create mode 100644 html/includes/renderer-dom.php create mode 100644 html/includes/renderer-general-import.php create mode 100644 html/includes/renderer-general-output.php (limited to 'html/includes') diff --git a/html/includes/config.php b/html/includes/config.php index 7b086f6..2e52f98 100755 --- a/html/includes/config.php +++ b/html/includes/config.php @@ -16,7 +16,8 @@ $import_homedir = ''; // Use the MySQL temporary tables feature? // Available since MySQL 3.23 - requires CREATE TEMPORARY TABLE privilege since 4.0.2 -$import_use_temporary_tables = true; // set to true if available +// No longer supported from utstats version 4.3 onwards. Left here for historical purposes. +$import_use_temporary_tables = false; // Do not set to true unless all jpgraph import changes have been disabled. // Use temporary heap tables? // This will (at any cost) keep the entire table in RAM and may speed and/or fuck things up @@ -183,4 +184,62 @@ $ftp_passive[$i] = true; // Use passive transfer mode for this connection? $ftp_delete[$i] = true; // Delete logs after download? */ +// This section is for stats graphs as of version 4.3 +$renderer_folder = "renderings"; +$renderer_width = 350; +$renderer_heigth = 250; +$renderer_color['team'][0][0] = '#ff3333'; // team red color 1 +$renderer_color['team'][0][1] = '#cc0000'; // team red color 2 +$renderer_color['team'][1][0] = '#0080ff'; // team blue color 1 +$renderer_color['team'][1][1] = '#0000cc'; // team blue color 2 +$renderer_color['team'][2][0] = '#88d8b0'; // team green color 1 +$renderer_color['team'][2][1] = '#009f50'; // team green color 2 +$renderer_color['team'][3][0] = '#ffeead'; // team gold color 1 +$renderer_color['team'][3][1] = '#e5b021'; // team gold color 2 +$renderer_color['player'][0][0] = '#a7d848'; // player 1 color 1 +$renderer_color['player'][0][1] = '#98be44'; // player 1 color 2 +$renderer_color['player'][1][0] = '#6ccdd0'; // player 2 color 1 +$renderer_color['player'][1][1] = '#66af9f'; // player 2 color 2 +$renderer_color['player'][2][0] = '#ffce59'; // player 3 color 1 +$renderer_color['player'][2][1] = '#ffa65a'; // player 3 color 2 +$renderer_color['player'][3][0] = '#fba263'; // player 4 color 1 +$renderer_color['player'][3][1] = '#eb7254'; // player 4 color 2 +$renderer_color['player'][4][0] = '#fb6370 '; // player 5 color 1 +$renderer_color['player'][4][1] = '#fb6363'; // player 5 color 2 +$renderer_color['background'] = '#262626';// background color 1 +$renderer_color['band'][0] = '#666666';// band color 1 +$renderer_color['band'][1] = '#515151';// band color 2 +$renderer_color['heading'] = '#bbdeff';// font heading +$renderer_color['font'] = '#999999';// font other +$renderer_color['amp'] = '#aa02db';// color amp +$renderer_color_transparancy = 0.3;// color amp + +define("TIMERATIO", 1.09863333333333333333333333333333333333333333333333333333333); + +define("RENDERER_CHARTTYPE_LINE", "line"); +define("RENDERER_CHARTTYPE_COLUMN", "column"); +define("RENDERER_CHARTTYPE_BAR", "bar"); +define("RENDERER_CHARTTYPE_LINESTEP", "linestep"); +define("RENDERER_CHARTTYPE_LINECOLUMN", "linecolumn"); +define("RENDERER_CHARTTYPE_LINESTEPCOLUMN", "linestepcolumn"); +define("RENDERER_CHARTTYPE_RADAR", "radar"); + +define("RENDERER_CHART_CTF_TEAMSCORE", 10); +define("RENDERER_CHART_CTF_GRABBREAKDOWN", 11); + +define("RENDERER_CHART_DOM_SCOREDERIV", 21); + +define("RENDERER_CHART_FRAGS_TEAMSCORE", 90); +define("RENDERER_CHART_FRAGS_TEAMDERIV", 91); +define("RENDERER_CHART_FRAGS_TEAMNORMAL", 92); +define("RENDERER_CHART_FRAGS_PLAYERSCORE", 93); +define("RENDERER_CHART_FRAGS_PLAYERDERIV", 94); +define("RENDERER_CHART_FRAGS_PLAYERNORMAL", 95); +define("RENDERER_CHART_FRAGS_PLAYERSCORE5", 96); +define("RENDERER_CHART_FRAGS_PLAYERNORMAL5", 97); + +define("RENDERER_CHART_ITEMS_TEAMPICKUPS", 100); +define("RENDERER_CHART_ITEMS_PLAYERPICKUPS", 101); +define("RENDERER_CHART_ITEMS_AMPRUNS", 102); + ?> diff --git a/html/includes/css/themes/tooltipster-light.css b/html/includes/css/themes/tooltipster-light.css new file mode 100644 index 0000000..945aa69 --- /dev/null +++ b/html/includes/css/themes/tooltipster-light.css @@ -0,0 +1,12 @@ +.tooltipster-light { + border-radius: 5px; + border: 1px solid #cccccc; + background: #ededed; + color: #666666; +} +.tooltipster-light .tooltipster-content { + font-family: Arial, sans-serif; + font-size: 14px; + line-height: 16px; + padding: 8px 10px; +} \ No newline at end of file diff --git a/html/includes/css/themes/tooltipster-noir.css b/html/includes/css/themes/tooltipster-noir.css new file mode 100644 index 0000000..548b245 --- /dev/null +++ b/html/includes/css/themes/tooltipster-noir.css @@ -0,0 +1,12 @@ +.tooltipster-noir { + border-radius: 0px; + border: 3px solid #2c2c2c; + background: #fff; + color: #2c2c2c; +} +.tooltipster-noir .tooltipster-content { + font-family: 'Georgia', serif; + font-size: 14px; + line-height: 16px; + padding: 8px 10px; +} \ No newline at end of file diff --git a/html/includes/css/themes/tooltipster-punk.css b/html/includes/css/themes/tooltipster-punk.css new file mode 100644 index 0000000..0b7362c --- /dev/null +++ b/html/includes/css/themes/tooltipster-punk.css @@ -0,0 +1,12 @@ +.tooltipster-punk { + border-radius: 5px; + border-bottom: 3px solid #f71169; + background: #2a2a2a; + color: #fff; +} +.tooltipster-punk .tooltipster-content { + font-family: 'Courier', monospace; + font-size: 14px; + line-height: 16px; + padding: 8px 10px; +} \ No newline at end of file diff --git a/html/includes/css/themes/tooltipster-shadow.css b/html/includes/css/themes/tooltipster-shadow.css new file mode 100644 index 0000000..e869c5e --- /dev/null +++ b/html/includes/css/themes/tooltipster-shadow.css @@ -0,0 +1,12 @@ +.tooltipster-shadow { + border-radius: 5px; + background: #fff; + box-shadow: 0px 0px 14px rgba(0,0,0,0.3); + color: #2c2c2c; +} +.tooltipster-shadow .tooltipster-content { + font-family: 'Arial', sans-serif; + font-size: 14px; + line-height: 16px; + padding: 8px 10px; +} \ No newline at end of file diff --git a/html/includes/css/tooltipster.css b/html/includes/css/tooltipster.css new file mode 100644 index 0000000..14c70d0 --- /dev/null +++ b/html/includes/css/tooltipster.css @@ -0,0 +1,283 @@ +/* This is the default Tooltipster theme (feel free to modify or duplicate and create multiple themes!): */ +.tooltipster-default { + border-radius: 5px; + border: 1px solid #1e1e1e; + background: -webkit-linear-gradient(#3b383b, #1e1e1e); /* For Safari 5.1 to 6.0 */ + background: -o-linear-gradient(#3b383b, #1e1e1e); /* For Opera 11.1 to 12.0 */ + background: -moz-linear-gradient(#3b383b, #1e1e1e); /* For Firefox 3.6 to 15 */ + background: linear-gradient(#3b383b, #1e1e1e); /* Standard syntax */ + color: #fff; + cursor: pointer; + -webkit-box-shadow: 10px 10px 26px -10px rgba(0,0,0,0.75); + -moz-box-shadow: 10px 10px 26px -10px rgba(0,0,0,0.75); + box-shadow: 10px 10px 26px -10px rgba(0,0,0,0.75); + max-width: 400px; +} + +/* Use this next selector to style things like font-size and line-height: */ +.tooltipster-default .tooltipster-content { + font-family: GothamLight, sans-serif; + font-size: 14px; + line-height: 16px; + padding: 8px 10px; + overflow: hidden; +} + +/* This next selector defines the color of the border on the outside of the arrow. This will automatically match the color and size of the border set on the main tooltip styles. Set display: none; if you would like a border around the tooltip but no border around the arrow */ +.tooltipster-default .tooltipster-arrow .tooltipster-arrow-border { + /* border-color: ... !important; */ +} + + +/* If you're using the icon option, use this next selector to style them */ +.tooltipster-icon { + cursor: pointer; + margin-left: 4px; +} + + + + + + + + +/* This is the base styling required to make all Tooltipsters work */ +.tooltipster-base { + padding: 0; + font-size: 0; + line-height: 0; + position: absolute; + left: 0; + top: 0; + z-index: 9999999; + pointer-events: none; + width: auto; + overflow: visible; + +} +.tooltipster-base .tooltipster-content { + overflow: hidden; +} + + +/* These next classes handle the styles for the little arrow attached to the tooltip. By default, the arrow will inherit the same colors and border as what is set on the main tooltip itself. */ +.tooltipster-arrow { + display: block; + text-align: center; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: -1; +} +.tooltipster-arrow span, .tooltipster-arrow-border { + display: block; + width: 0; + height: 0; + position: absolute; +} +.tooltipster-arrow-top span, .tooltipster-arrow-top-right span, .tooltipster-arrow-top-left span { + border-left: 8px solid transparent !important; + border-right: 8px solid transparent !important; + border-top: 8px solid; + bottom: -7px; +} +.tooltipster-arrow-top .tooltipster-arrow-border, .tooltipster-arrow-top-right .tooltipster-arrow-border, .tooltipster-arrow-top-left .tooltipster-arrow-border { + border-left: 9px solid transparent !important; + border-right: 9px solid transparent !important; + border-top: 9px solid; + bottom: -7px; +} + +.tooltipster-arrow-bottom span, .tooltipster-arrow-bottom-right span, .tooltipster-arrow-bottom-left span { + border-left: 8px solid transparent !important; + border-right: 8px solid transparent !important; + border-bottom: 8px solid; + top: -7px; +} +.tooltipster-arrow-bottom .tooltipster-arrow-border, .tooltipster-arrow-bottom-right .tooltipster-arrow-border, .tooltipster-arrow-bottom-left .tooltipster-arrow-border { + border-left: 9px solid transparent !important; + border-right: 9px solid transparent !important; + border-bottom: 9px solid; + top: -7px; +} +.tooltipster-arrow-top span, .tooltipster-arrow-top .tooltipster-arrow-border, .tooltipster-arrow-bottom span, .tooltipster-arrow-bottom .tooltipster-arrow-border { + left: 0; + right: 0; + margin: 0 auto; +} +.tooltipster-arrow-top-left span, .tooltipster-arrow-bottom-left span { + left: 6px; +} +.tooltipster-arrow-top-left .tooltipster-arrow-border, .tooltipster-arrow-bottom-left .tooltipster-arrow-border { + left: 5px; +} +.tooltipster-arrow-top-right span, .tooltipster-arrow-bottom-right span { + right: 6px; +} +.tooltipster-arrow-top-right .tooltipster-arrow-border, .tooltipster-arrow-bottom-right .tooltipster-arrow-border { + right: 5px; +} +.tooltipster-arrow-left span, .tooltipster-arrow-left .tooltipster-arrow-border { + border-top: 8px solid transparent !important; + border-bottom: 8px solid transparent !important; + border-left: 8px solid; + top: 50%; + margin-top: -7px; + right: -7px; +} +.tooltipster-arrow-left .tooltipster-arrow-border { + border-top: 9px solid transparent !important; + border-bottom: 9px solid transparent !important; + border-left: 9px solid; + margin-top: -8px; +} +.tooltipster-arrow-right span, .tooltipster-arrow-right .tooltipster-arrow-border { + border-top: 8px solid transparent !important; + border-bottom: 8px solid transparent !important; + border-right: 8px solid; + top: 50%; + margin-top: -7px; + left: -7px; +} +.tooltipster-arrow-right .tooltipster-arrow-border { + border-top: 9px solid transparent !important; + border-bottom: 9px solid transparent !important; + border-right: 9px solid; + margin-top: -8px; +} + + +/* Some CSS magic for the awesome animations - feel free to make your own custom animations and reference it in your Tooltipster settings! */ + +.tooltipster-fade { + opacity: 0; + -webkit-transition-property: opacity; + -moz-transition-property: opacity; + -o-transition-property: opacity; + -ms-transition-property: opacity; + transition-property: opacity; +} +.tooltipster-fade-show { + opacity: 1; +} + +.tooltipster-grow { + -webkit-transform: scale(0,0); + -moz-transform: scale(0,0); + -o-transform: scale(0,0); + -ms-transform: scale(0,0); + transform: scale(0,0); + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + -o-transition-property: -o-transform; + -ms-transition-property: -ms-transform; + transition-property: transform; + -webkit-backface-visibility: hidden; +} +.tooltipster-grow-show { + -webkit-transform: scale(1,1); + -moz-transform: scale(1,1); + -o-transform: scale(1,1); + -ms-transform: scale(1,1); + transform: scale(1,1); + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); +} + +.tooltipster-swing { + opacity: 0; + -webkit-transform: rotateZ(4deg); + -moz-transform: rotateZ(4deg); + -o-transform: rotateZ(4deg); + -ms-transform: rotateZ(4deg); + transform: rotateZ(4deg); + -webkit-transition-property: -webkit-transform, opacity; + -moz-transition-property: -moz-transform; + -o-transition-property: -o-transform; + -ms-transition-property: -ms-transform; + transition-property: transform; +} +.tooltipster-swing-show { + opacity: 1; + -webkit-transform: rotateZ(0deg); + -moz-transform: rotateZ(0deg); + -o-transform: rotateZ(0deg); + -ms-transform: rotateZ(0deg); + transform: rotateZ(0deg); + -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 1); + -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4); + -moz-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4); + -ms-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4); + -o-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4); + transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4); +} + +.tooltipster-fall { + top: 0; + -webkit-transition-property: top; + -moz-transition-property: top; + -o-transition-property: top; + -ms-transition-property: top; + transition-property: top; + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); +} +.tooltipster-fall-show { +} +.tooltipster-fall.tooltipster-dying { + -webkit-transition-property: all; + -moz-transition-property: all; + -o-transition-property: all; + -ms-transition-property: all; + transition-property: all; + top: 0px !important; + opacity: 0; +} + +.tooltipster-slide { + left: -40px; + -webkit-transition-property: left; + -moz-transition-property: left; + -o-transition-property: left; + -ms-transition-property: left; + transition-property: left; + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1); + -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); + transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15); +} +.tooltipster-slide.tooltipster-slide-show { +} +.tooltipster-slide.tooltipster-dying { + -webkit-transition-property: all; + -moz-transition-property: all; + -o-transition-property: all; + -ms-transition-property: all; + transition-property: all; + left: 0px !important; + opacity: 0; +} + + +/* CSS transition for when contenting is changing in a tooltip that is still open. The only properties that will NOT transition are: width, height, top, and left */ +.tooltipster-content-changing { + opacity: 0.5; + -webkit-transform: scale(1.1, 1.1); + -moz-transform: scale(1.1, 1.1); + -o-transform: scale(1.1, 1.1); + -ms-transform: scale(1.1, 1.1); + transform: scale(1.1, 1.1); +} diff --git a/html/includes/domstats.php b/html/includes/domstats.php new file mode 100644 index 0000000..dbdd3f7 --- /dev/null +++ b/html/includes/domstats.php @@ -0,0 +1,719 @@ + ''"; + $q_player = mysql_query($sql_player) or die(mysql_error()); + + while ($r_player = mysql_fetch_array($q_player)) { + $playerid = $r_player[col4]; + + // Get players last name used + $r_player2 = small_query("SELECT col3 FROM uts_temp_$uid WHERE col1 = 'player' AND col2 = 'rename' AND col4 = $playerid ORDER BY id DESC LIMIT 0,1"); + $playername = addslashes($r_player2[col3]); + + // Get players last team + $r_player3 = small_query("SELECT col4 FROM uts_temp_$uid WHERE col1 = 'player' AND col2 = 'TeamChange' AND col3 = $playerid AND col4 != 255 ORDER BY id DESC LIMIT 0,1"); + $playerteam = $r_player3[col4]; + + $playernames[$playerid] = $playername; + $playerteams[$playerid] = $playerteam; + } + + return array($playernames,$playerteams); + +} + +/* +Get time game starts, game ends, and ratio compared to real time +@return $time_gamestart, $time_gameend, $time_ratio_correction (difference in ut time & real time, typically 110%) +*/ +function getGameStartEndRatio($uid) { + + // gather game start & end time + $q_logdom = mysql_query("SELECT col0 FROM uts_temp_$uid WHERE col1='game_start' OR col1='game_end' ORDER BY id ASC")or die(mysql_error()); + + $time_gamestart = mysql_result($q_logdom,0); + $time_gameend = mysql_result($q_logdom,1); + $time_ratio_correction = ($time_gameend-$time_gamestart)/1200; + + return array($time_gamestart, $time_gameend, $time_ratio_correction); +} + +/* +Helper function to create the temporary table used for dom stats +*/ +function createEmptyTempTable($table_name) { + + $sqlCreateTable = " + CREATE TEMPORARY TABLE `$table_name` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `cp` varchar(254) NOT NULL, + `teamid` int(11) NOT NULL, + `playerid` int(11) NOT NULL, + `playername` varchar(254) NOT NULL, + `start` float NOT NULL, + `end` float NOT NULL, + `time` float NOT NULL, + `scoret0` float NOT NULL, + `scoret1` float NOT NULL, + `realTimeEnd` float NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=MyISAM + "; + mysql_query($sqlCreateTable) or die(mysql_error()); +} + +/* +Create & populate the dom stats table +@return name of temporary table +*/ +function generateTempTable($uid) { + global $playernames; + global $playerteams; + global $time_gamestart; + global $time_gameend; + global $time_ratio_correction; + + $tempTableName = "uts_tempidom_".$uid; + + createEmptyTempTable($tempTableName); + + // iterate over cp's. also capture game-end event as a quick hack to also do final iteration over final cp + $q_logdom = mysql_query("SELECT * FROM uts_temp_$uid WHERE col1='controlpoint_capture' OR col1='game_end' ORDER BY col1, col2, id ASC")or die(mysql_error()); + + $prev_time = 0; + + // dynamicly create insert query to populate the table in 1 go, instead of multiple database calls + $insertQuery = "INSERT INTO $tempTableName (cp, teamid, playerid, playername, start, end, time,scoret0,scoret1,realTimeEnd) VALUES"; + + // basically loop over all capture events per CP. Each time calculate how long the previous owner had the point and translate this to dom points + while($r_logdom = mysql_fetch_array($q_logdom)) { + $points[0] = 0; + $points[1] = 0; + $ticks[0] = 0; + $ticks[1] = 0; + + $start_time = $prev_time; + + $r_cp = $r_logdom['col2']; + $r_time = $r_logdom['col0']; + + // skip first capture event - no dom points given at start of map since no-one has cp + if($prev_time > 0) { + + // if switching to other cp + if($prev_cp != $r_cp) { + $end_time = $time_gameend; // take game end time to calculate time cp was taken, since it's the last time it's taken + extra tick for end time + + } else { + $end_time = $r_time; + } + + $time_diff = ($end_time - $start_time); + + // point has to be yours for at least a second before it starts to add points + if($time_diff >= 1) { + + // after this second, it will start to add points during each time the timer runs (= each second) + // thus, first run of timer is ceil of start time + // also, floor of end time since having the point after the timer ran, but not until the next tick = no points + // timing in log does not account for gamespeed, typically 1.1 ratio, which is corrected in these times + // test was done to save the actual tick times based upon the dom_points stats event (happens each 5 ticks), but this doesn't result in significant better results to be worth the effort + + // save amount of timer 'ticks' that generate a score of 0.2 + $ticks[$r_teamid] = (floor($end_time/$time_ratio_correction)-ceil($start_time/$time_ratio_correction)); + + } + + // if no tick happened, insert the event with 0 points + if($ticks[$r_teamid]==0) { + + $realTimeEnd=($start_time-$time_gamestart)/$time_ratio_correction/60; + $insertQuery .= " ('$prev_cp', '$r_teamid', '$r_pid', '$r_pname', '$start_time', '$end_time', '$time_diff', '".$points[0]."', '".$points[1]."', '$realTimeEnd'),"; + + // if ticks happened, insert each seperate tick as an event + } else { + + for($i=1;($ticks[$r_teamid]+1-$i) > 0;$i++) { + + $realTimeEnd=($start_time+$time_diff/$ticks[$r_teamid]*$i-$time_gamestart)/$time_ratio_correction/60; + $points[$r_teamid] = 0.2; + + $insertQuery .= " ('$prev_cp', '$r_teamid', '$r_pid', '$r_pname', '$start_time', '$end_time', '$time_diff', '".$points[0]."', '".$points[1]."', '$realTimeEnd'),"; + + } + } + + } + + // save data for current capture event + $prev_time = $r_time; + $prev_cp = $r_cp; + + $r_event = $r_logdom['col1']; + $r_pid = $r_logdom['col3']; + $r_teamid = mysql_real_escape_string($playerteams[$r_pid]); + $r_pname = mysql_real_escape_string($playernames[$r_pid]); + + } + + // populate table + $insertQuery = rtrim($insertQuery,","); + mysql_query($insertQuery) or die(mysql_error()); + + return $tempTableName; + +} + +/* +Generate times when amp was taken +@return $amps[$team][$start_time,$end_time, $pid] +*/ +function generateAmpTimes($uid) { + global $playernames; + global $playerteams; + global $time_gamestart; + global $time_gameend; + global $time_ratio_correction; + + $amps = array(); + $prev_time = array(); + + // Get activate & deactivate times & players + $q_amps = mysql_query("SELECT col0,col1,col3 FROM uts_temp_$uid WHERE col2='Damage Amplifier' AND (col1='item_activate' OR col1='item_deactivate') ORDER BY id ASC"); + while($r_amps = mysql_fetch_array($q_amps)) { + $time = ($r_amps[0]-$time_gamestart)/$time_ratio_correction/60; + $event = $r_amps[1]; + $pid = $r_amps[2]; + + // If amp is deactivated, calculate the time it was used + if($event == "item_deactivate") { + $amps[$playerteams[$pid]][] = array($prev_time[$pid], $time,$pid); + $prev_time[$pid] = 0; + + // If amp is activated & none yet acquired, save the time of the start of this amp run + } else if($prev_time[$pid] == 0) { + $prev_time[$pid] = $time; + } + } + + return $amps; +} + +/* +Function to render the chart with amp runs +*/ +function renderAmpBars($uid,$tempTableName) { + global $playernames; + global $ampTimes; + global $matchid; + global $domimage_color; + global $domimages_folder; + global $domimage_width; + global $domimage_heigth; + + // Iterate over amp runs + for($i=0;$i<2;$i++) { + foreach ($ampTimes[$i] as $ampTaken) { + $ampStart = $ampTaken[0]; + $ampEnd = $ampTaken[1]; + $pid = $ampTaken[2]; + + // Only save amp runs longer than 20seconds + if($ampEnd > ($ampStart+.33)) { + + // Get scores during amprun + $q_scoresDuringAmp = mysql_query("SELECT SUM(scoret0),SUM(scoret1) FROM $tempTableName WHERE realTimeEnd > $ampStart AND realTimeEnd < $ampEnd"); + $r_scoresDuringAmps = mysql_fetch_array($q_scoresDuringAmp); + + $netPoints = $r_scoresDuringAmps[$i] - $r_scoresDuringAmps[1-$i]; + + // Process time for readable label + $totalTime = $ampEnd-$ampStart; + $totalTimeMinutes = floor($totalTime); + $totalTimeSeconds = round(($totalTime-$totalTimeMinutes)*60,0); + + $timeLabel = ""; + if($totalTimeMinutes>0) { $timeLabel .= $totalTimeMinutes."m"; } + if($totalTimeSeconds>0) { $timeLabel .= $totalTimeSeconds."s"; } + + $playerName = $playernames[$pid]; + + $ampRun['start'] = $ampStart; + $ampRun['label'] = substr($playerName,0,15)." (".$timeLabel.")"; + $ampRun['points'] = $netPoints; + $ampRun['team'] = $i; + + $data[] = $ampRun; + } + } + } + + if(count($data)>0) { + + // Sort ampruns not on teams, but on start time, to make sure they are plotted chronocologicstic + $data = array_sort($data,'start'); + + $maxValue=0; + // Process the ampruns to map it to 2 differnt bar plots per team + foreach ($data as $ampRun) { + $labels[] = $ampRun['label']; + $values[$ampRun['team']][] = $ampRun['points']; + + $posValue = $ampRun['points']>0? $ampRun['points'] : $ampRun['points']*-1; + + if($posValue>$maxValue) + $maxValue = $posValue; + + // Add 0 value for other team to ensure only 1 bar is plotted each time (either team 0 or team 1) + $values[1-$ampRun['team']][] = 0; + } + + $tickInterval = $maxValue>15?10:5; + $maxValue = $tickInterval*ceil($maxValue/$tickInterval); + + // Create the graph + // Some commands to enable horizontal bars & moved axis for proper formatting + $graph = new Graph($domimage_width+8,$domimage_heigth+8); + $graph->SetScale('textlin',$maxValue*-1,$maxValue); + $graph->SetTickDensity(TICKD_SPARSE); + $graph->Set90AndMargin('20','15','30','30'); + $graph->SetMarginColor($domimage_color['background']); + $graph->SetColor($domimage_color['background']); + $graph->SetFrame(true,$domimage_color['background'],0); + $graph->ygrid->SetFill(true,$domimage_color['band'][0],$domimage_color['band'][1]); + $graph->ygrid->SetColor($domimage_color['background']); + + $graph->title->Set('Net Score Amp Runs'); + $graph->title->SetFont(FF_VERDANA,FS_BOLD); + $graph->title->SetColor($domimage_color['heading']); + + $graph->xaxis->SetPos('min'); + $graph->xaxis->SetTickLabels($labels); + $graph->xaxis->SetFont(FF_VERDANA,FS_NORMAL,7); + $graph->xaxis->SetColor($domimage_color['font']); + $graph->xaxis->SetLabelAlign('left','center'); + $graph->xaxis->SetColor($domimage_color['background'],$domimage_color['font']); + + $graph->yaxis->SetPos('max'); + $graph->yaxis->SetLabelAlign('center','top'); + $graph->yaxis->SetLabelSide(SIDE_RIGHT); + $graph->yaxis->SetTickSide(SIDE_LEFT); + $graph->yaxis->scale->ticks->set($tickInterval); + $graph->yaxis->SetColor($domimage_color['background'],$domimage_color['font']); + + if(count($values[0])>0) { + $b1plot = new BarPlot($values[0]); + $graph->Add($b1plot); + $b1plot->SetFillGradient($domimage_color['team'][0][0],$domimage_color['team'][0][1],GRAD_HOR); + $b1plot->SetColor($domimage_color['team'][0][0]); + + } if(count($values[1])>0) { + $b2plot = new BarPlot($values[1]); + $graph->Add($b2plot); + $b2plot->SetFillGradient($domimage_color['team'][1][0],$domimage_color['team'][1][1],GRAD_HOR); + $b2plot->SetColor($domimage_color['team'][1][0]); + } + + $graph->Stroke($domimages_folder."/".$matchid."-ampruns.png"); + } +} + +/* +Generate the chart with pickups +*/ +function renderDataPickups($uid) { + global $matchid; + global $domimage_color; + global $domimages_folder; + global $domimage_width; + global $domimage_heigth; + + $q_pickups = mysql_query("SELECT SUM(pu_belt), SUM(pu_keg), SUM(pu_pads), SUM(pu_armour), SUM(pu_amp) FROM uts_player as p WHERE matchid = $matchid GROUP BY team") or die(mysql_error()); + + while($r_pickups = mysql_fetch_row($q_pickups)) { + $preData[] = $r_pickups; + } + + $anyPickupDone = false; + + // Process data to convert these to percentages + // Normal numbers don't plot nicely (fe. pads getting much higher pickups due to lower spawn time + for($i=0;$i<5;$i++) { + if($preData[0][$i]>0) { + $data[0][$i] = round($preData[0][$i]/($preData[0][$i]+$preData[1][$i])*100,0); + $data[1][$i] = 100-$data[0][$i]; + $anyPickupDone = true; + } else if($preData[1][$i]>0) { + $data[0][$i] = 0; + $data[1][$i] = 100; + $anyPickupDone = true; + } else { + $data[0][$i] = 0; + $data[1][$i] = 0; + } + } + + if($anyPickupDone) { + // Plot radargraph + $titles = array('belt','keg','pads','armour','amp'); + $graph = new RadarGraph ($domimage_width+8,$domimage_heigth+8); + $graph->SetScale('lin',0,100); + $graph->yscale->ticks->Set(25,5); + $graph->setMargin(30,30,30,30); + $graph->SetMarginColor($domimage_color['background']); + $graph->SetColor($domimage_color['background']); + $graph->SetFrame(true,$domimage_color['background'],0); + $graph->title->Set('Pickups %'); + $graph->title->SetFont(FF_VERDANA,FS_BOLD); + $graph->title->SetColor($domimage_color['heading']); + $graph->HideTickMarks(); + $graph->axis->HideLabels(); + + $graph->SetTitles($titles); + $graph->axis->title->SetFont(FF_VERDANA,FS_NORMAL,8); + $graph->axis->title->SetColor($domimage_color['font']); + $graph->grid->Show(true,true); + $graph->grid->SetLineStyle('dashed'); + + // Seperate plot within radar per team + $plot1 = new RadarPlot($data[0]); + $plot2 = new RadarPlot($data[1]); + $graph->Add($plot1); + $graph->Add($plot2); + + $plot1->SetFillColor($domimage_color['team'][0][0].'@0.5'); + $plot1->SetColor($domimage_color['team'][0][0]); + $plot1->SetLineWeight(2); + $plot2->SetFillColor($domimage_color['team'][1][0].'@0.5'); + $plot2->SetColor($domimage_color['team'][1][0]); + $plot2->SetLineWeight(2); + + $graph->Stroke($domimages_folder."/".$matchid."-pickups.png"); + } +} + +/* +Render dom points over time & net rate of change per minute over all cp's +*/ +function renderDataTotal($uid,$tempTableName) { + $query = "SELECT t.realTimeEnd,@t0sum := @t0sum + t.scoret0 AS cumulScoret0,@t1sum := @t1sum + t.scoret1 AS cumulScoret1 FROM $tempTableName t JOIN (SELECT @t0sum := 0) r JOIN (SELECT @t1sum := 0) s ORDER BY realTimeEnd ASC"; + $appex = "total"; + + renderData($uid,$tempTableName,$query,$appex,"Total score",""); +} + +/* +Render dom points over time & net rate of change per minute per cp +*/ +function renderDataCPs($uid,$tempTableName) { + $q_cps = mysql_query("SELECT DISTINCT(cp) FROM $tempTableName"); + + $i=0; + while($r_cps = mysql_fetch_array($q_cps)) { + $r_cp = $r_cps[0]; + $query = "SELECT t.realTimeEnd,@t0sum := @t0sum + t.scoret0 AS cumulScoret0,@t1sum := @t1sum + t.scoret1 AS cumulScoret1 FROM $tempTableName t JOIN (SELECT @t0sum := 0) r JOIN (SELECT @t1sum := 0) s WHERE t.CP = '$r_cp' ORDER BY realTimeEnd ASC"; + $appex = "cp".$i++; + renderData($uid,$tempTableName,$query,$appex,"Score CP ".$r_cp,$r_cp); + + } +} + +/* +Render dom points over time & net rate of change per minute +*/ +function renderData($uid,$tempTableName,$query,$appex,$title,$cp) { + global $matchid; + global $domimage_color; + global $domimages_folder; + global $domimage_width; + global $domimage_heigth; + + // Use helper function to parse the data into different datasets for charts + list($datax,$datay1,$datay2,$derivx,$derivy1,$derivy2) = parseData($query); + + // If this is a cp plot, ensure enough space for plotting the names underneath + if(strlen($cp)>0) { + + $g1heigth = $domimage_heigth*.65; + $g2heigth = $domimage_heigth*.35; + $g2marginlow = 50; + + // Else, use all space + } else { + + $g1heigth = $domimage_heigth*.75; + $g2heigth = $domimage_heigth*.25; + $g2marginlow = 10; + + } + + // Dom points over time per team + $graph1 = createGraph($title,$domimage_width,$g1heigth,array(30,10,30,30),"linlin"); + $sp11 = generateScatterLink($datax, $datay1,$domimage_color['team'][0][0],'FCallbackRedAmp'); + $sp12 = generateScatterLink($datax, $datay2,$domimage_color['team'][1][0],'FCallbackBlueAmp'); + $graph1->Add($sp11); + $graph1->Add($sp12); + + // Net rate of change per minute + $graph2 = createGraph("",$domimage_width,$g2heigth,array(30,10,5,$g2marginlow),"linlin"); + $graph2->xaxis->HideLabels(); + + $b1plot = new BarPlot($derivy1,$derivx); + $b2plot = new BarPlot($derivy2,$derivx); + + $graph2->Add($b1plot); + $graph2->Add($b2plot); + + $b1plot->SetFillGradient($domimage_color['team'][0][0],$domimage_color['team'][0][1],GRAD_HOR); + $b1plot->SetColor($domimage_color['team'][0][0]); + $b1plot->SetWidth(0.85); + $b2plot->SetFillGradient($domimage_color['team'][1][0],$domimage_color['team'][1][1],GRAD_HOR); + $b2plot->SetColor($domimage_color['team'][1][0]); + $b2plot->SetWidth(0.85); + + // If this is a cp plot, render the names + if(strlen($cp) > 0) { + renderNamesCP($tempTableName,$cp,$graph2,$domimage_width,$g2heigth); + } + + // Combine both graphs into one + $mgraph = new MGraph(); + $xpos1=0;$ypos1=0; + $xpos2=0;$ypos2=$g1heigth; + $mgraph->Add($graph1,$xpos1,$ypos1); + $mgraph->Add($graph2,$xpos2,$ypos2); + $mgraph->SetFillColor($domimage_color['background']); + + $gdImgHandler = $mgraph->Stroke(_IMG_HANDLER); + + $fileName = $domimages_folder."/".$matchid."-".$appex.".png"; + $mgraph->Stroke($fileName); +} + +/* +Helper function to parse the data for the main renderData +*/ +function parseData($query) { + $q_result = mysql_query($query) or die(mysql_error()); + + $prevx = 0; + $prevy1 = 0; + $prevy2 = 0; + $smallcounter = 1/3; + $counter = 1; + + while($data = mysql_fetch_array($q_result)) { + + // Prep data for dom points over time + // Only save the data each $smallcounter interval, to optimize rendering time + if($data[0]>=$smallcounter) { + + $datax[] = $data[0]; + $datay1[] = $data[1]; + $datay2[] = $data[2]; + + $smallcounter+=1/3; + } + + // Prep data for net change over time + // Only save the data each integer interval, since we want the value per minute + // Start at 0.5, to ensure proper alignment with graph above (cheap hack) + if($data[0]>=$counter) { + $derivx[] = $counter-1; + + $derivy1pre = $data[1]-$prevy1; + $derivy2pre = $data[2]-$prevy2; + + $derivy1post = $derivy1pre-$derivy2pre; + $derivy2post = $derivy2pre-$derivy1pre; + + $derivy1[] = $derivy1post>0 ? $derivy1post : 0; + $derivy2[] = $derivy2post>0 ? $derivy2post : 0; + + $prevy1 = $data[1]; + $prevy2 = $data[2]; + + $counter++; + } + } + + return array($datax,$datay1,$datay2,$derivx,$derivy1,$derivy2); +} + +/* +Render the names of players that played the cp +*/ +function renderNamesCP($tempTableName,$appex,$graph,$width,$height) { + global $domimage_color; + + $appex = mysql_real_escape_string($appex); + + $q_namesPerCP = mysql_query("SELECT playername, COUNT( playername ) AS cplayer, MAX( teamid ) AS tid, AVG( realTimeEnd ) AS ati FROM $tempTableName WHERE cp = '$appex' GROUP BY playername ORDER BY tid,ati") or die(mysql_error()); + + $yTeam[0][0] = 45; + $yTeam[0][1] = 35; + $yTeam[1][0] = 20; + $yTeam[1][1] = 10; + $prevTeam = -1; + + while($r_namesPerCP = mysql_fetch_array($q_namesPerCP)) { + $playerName = substr($r_namesPerCP[0],0,20); + $timesTouched = $r_namesPerCP[1]; + $teamid = $r_namesPerCP[2]; + $avgTime = $r_namesPerCP[3]; + + // Only plot the playername if he touched the cp at least 60 times + if(strlen($playerName)>0 && $timesTouched > 60) { + + $txt = new Text($playerName); + + // Names per team can be plotted on 2 different heights to ensure it doesn't become a mess on one line + // This bit of code ensures height is flipped each time + if($teamid == $prevTeam) { + $ypos = $height-$yTeam[$teamid][1]; + $prevTeam = -1; + } else { + $ypos = $height-$yTeam[$teamid][0]; + $prevTeam = $teamid; + } + + $color = $domimage_color['team'][$teamid][0]; + + // Plot name at average time, minus 25 (hack assuming most names are around 50 pixels) + $txt->SetPos($width/20*$avgTime-25,$ypos); + + $txt->SetColor($color); + $txt->SetFont(FF_VERDANA,FS_NORMAL,8); + $graph->AddText($txt); + } + + $prevAvgTime = $avgTime; + } + +} + +/* +Helper function to generate the graph object +*/ +function createGraph($title,$width,$height,$margin,$scale) { + global $domimage_color; + + $graph = new Graph($width,$height); + + $graph->SetScale($scale); + $graph->SetMargin($margin[0],$margin[1],$margin[2],$margin[3]); + $graph->SetMarginColor($domimage_color['background']); + $graph->SetColor($domimage_color['background']); + $graph->SetFrame(true,$domimage_color['background'],0); + + $graph->ygrid->SetFill(true,$domimage_color['band'][0],$domimage_color['band'][1]); + $graph->ygrid->SetColor($domimage_color['background']); + + $graph->yaxis->SetColor($domimage_color['background'],$domimage_color['font']); + $graph->xaxis->SetColor($domimage_color['background'],$domimage_color['font']); + + if(strlen($title)>0) { + $graph->title->Set($title); + $graph->title->SetFont(FF_VERDANA,FS_BOLD); + $graph->title->SetColor($domimage_color['heading']); + } + return $graph; +} + +/* +Helper function to generate the scatter plots +*/ +function generateScatterLink($datax, $datay, $color,$callback) { + $sp = new ScatterPlot($datay,$datax); + + $sp->link->Show(); + $sp->link->SetStyle('solid'); + $sp->link->SetWeight(3); + $sp->link->SetColor($color); + + if(strlen($callback) > 0) + $sp->mark->SetCallbackYX($callback); + + $sp->mark->SetType(MARK_FILLEDCIRCLE); + + return $sp; +} + +/* +Format functions for scatterplot to format based on team and whether amp was taken +*/ +function FCallbackRedAmp($bVal,$aVal) { + return FCallbackAmp($aVal,0); +} + +function FCallbackBlueAmp($bVal,$aVal) { + return FCallbackAmp($aVal,1); +} + +function FCallbackAmp($aVal, $team) { + global $ampTimes; + global $domimage_color; + + $size = 1; + $color = $domimage_color['team'][$team][0]; + + foreach ($ampTimes[$team] as $ampTaken) { + + if($aVal > $ampTaken[0] && $aVal < $ampTaken[1]) { + + $color = $domimage_color['amp']; + $size = 3; + break; + } + } + + return array($size,$color,$color); +} + +/* +Helper function to sort array on key, based on solution from the interwebs +*/ +function array_sort($array, $on) { + $new_array = array(); + $sortable_array = array(); + + if (count($array) > 0) { + foreach ($array as $k => $v) { + if (is_array($v)) { + foreach ($v as $k2 => $v2) { + if ($k2 == $on) { + $sortable_array[$k] = $v2; + } + } + } else { + $sortable_array[$k] = $v; + } + } + + asort($sortable_array); + + foreach ($sortable_array as $k => $v) { + $new_array[$k] = $array[$k]; + } + } + + return $new_array; +} +?> \ No newline at end of file diff --git a/html/includes/encoding.php b/html/includes/encoding.php new file mode 100644 index 0000000..a559a3b --- /dev/null +++ b/html/includes/encoding.php @@ -0,0 +1,304 @@ + + * @package Encoding + * @version 2.0 + * @link https://github.com/neitanod/forceutf8 + * @example https://github.com/neitanod/forceutf8 + * @license Revised BSD + */ +namespace ForceUTF8; +class Encoding { + const ICONV_TRANSLIT = "TRANSLIT"; + const ICONV_IGNORE = "IGNORE"; + const WITHOUT_ICONV = ""; + protected static $win1252ToUtf8 = array( + 128 => "\xe2\x82\xac", + 130 => "\xe2\x80\x9a", + 131 => "\xc6\x92", + 132 => "\xe2\x80\x9e", + 133 => "\xe2\x80\xa6", + 134 => "\xe2\x80\xa0", + 135 => "\xe2\x80\xa1", + 136 => "\xcb\x86", + 137 => "\xe2\x80\xb0", + 138 => "\xc5\xa0", + 139 => "\xe2\x80\xb9", + 140 => "\xc5\x92", + 142 => "\xc5\xbd", + 145 => "\xe2\x80\x98", + 146 => "\xe2\x80\x99", + 147 => "\xe2\x80\x9c", + 148 => "\xe2\x80\x9d", + 149 => "\xe2\x80\xa2", + 150 => "\xe2\x80\x93", + 151 => "\xe2\x80\x94", + 152 => "\xcb\x9c", + 153 => "\xe2\x84\xa2", + 154 => "\xc5\xa1", + 155 => "\xe2\x80\xba", + 156 => "\xc5\x93", + 158 => "\xc5\xbe", + 159 => "\xc5\xb8" + ); + protected static $brokenUtf8ToUtf8 = array( + "\xc2\x80" => "\xe2\x82\xac", + "\xc2\x82" => "\xe2\x80\x9a", + "\xc2\x83" => "\xc6\x92", + "\xc2\x84" => "\xe2\x80\x9e", + "\xc2\x85" => "\xe2\x80\xa6", + "\xc2\x86" => "\xe2\x80\xa0", + "\xc2\x87" => "\xe2\x80\xa1", + "\xc2\x88" => "\xcb\x86", + "\xc2\x89" => "\xe2\x80\xb0", + "\xc2\x8a" => "\xc5\xa0", + "\xc2\x8b" => "\xe2\x80\xb9", + "\xc2\x8c" => "\xc5\x92", + "\xc2\x8e" => "\xc5\xbd", + "\xc2\x91" => "\xe2\x80\x98", + "\xc2\x92" => "\xe2\x80\x99", + "\xc2\x93" => "\xe2\x80\x9c", + "\xc2\x94" => "\xe2\x80\x9d", + "\xc2\x95" => "\xe2\x80\xa2", + "\xc2\x96" => "\xe2\x80\x93", + "\xc2\x97" => "\xe2\x80\x94", + "\xc2\x98" => "\xcb\x9c", + "\xc2\x99" => "\xe2\x84\xa2", + "\xc2\x9a" => "\xc5\xa1", + "\xc2\x9b" => "\xe2\x80\xba", + "\xc2\x9c" => "\xc5\x93", + "\xc2\x9e" => "\xc5\xbe", + "\xc2\x9f" => "\xc5\xb8" + ); + protected static $utf8ToWin1252 = array( + "\xe2\x82\xac" => "\x80", + "\xe2\x80\x9a" => "\x82", + "\xc6\x92" => "\x83", + "\xe2\x80\x9e" => "\x84", + "\xe2\x80\xa6" => "\x85", + "\xe2\x80\xa0" => "\x86", + "\xe2\x80\xa1" => "\x87", + "\xcb\x86" => "\x88", + "\xe2\x80\xb0" => "\x89", + "\xc5\xa0" => "\x8a", + "\xe2\x80\xb9" => "\x8b", + "\xc5\x92" => "\x8c", + "\xc5\xbd" => "\x8e", + "\xe2\x80\x98" => "\x91", + "\xe2\x80\x99" => "\x92", + "\xe2\x80\x9c" => "\x93", + "\xe2\x80\x9d" => "\x94", + "\xe2\x80\xa2" => "\x95", + "\xe2\x80\x93" => "\x96", + "\xe2\x80\x94" => "\x97", + "\xcb\x9c" => "\x98", + "\xe2\x84\xa2" => "\x99", + "\xc5\xa1" => "\x9a", + "\xe2\x80\xba" => "\x9b", + "\xc5\x93" => "\x9c", + "\xc5\xbe" => "\x9e", + "\xc5\xb8" => "\x9f" + ); + static function toUTF8($text){ + /** + * Function \ForceUTF8\Encoding::toUTF8 + * + * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8. + * + * It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1. + * + * It may fail to convert characters to UTF-8 if they fall into one of these scenarios: + * + * 1) when any of these characters: ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞß + * are followed by any of these: ("group B") + * ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿ + * For example: %ABREPRESENT%C9%BB. «REPRESENTÉ» + * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) + * is also a valid unicode character, and will be left unchanged. + * + * 2) when any of these: àáâãäåæçèéêëìíîï are followed by TWO chars from group B, + * 3) when any of these: ðñòó are followed by THREE chars from group B. + * + * @name toUTF8 + * @param string $text Any string. + * @return string The same string, UTF8 encoded + * + */ + if(is_array($text)) + { + foreach($text as $k => $v) + { + $text[$k] = self::toUTF8($v); + } + return $text; + } elseif(is_string($text)) { + if ( function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2) { + $max = mb_strlen($text,'8bit'); + } else { + $max = strlen($text); + } + $buf = ""; + for($i = 0; $i < $max; $i++){ + $c1 = $text{$i}; + if($c1>="\xc0"){ //Should be converted to UTF8, if it's not UTF8 already + $c2 = $i+1 >= $max? "\x00" : $text{$i+1}; + $c3 = $i+2 >= $max? "\x00" : $text{$i+2}; + $c4 = $i+3 >= $max? "\x00" : $text{$i+3}; + if($c1 >= "\xc0" & $c1 <= "\xdf"){ //looks like 2 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2; + $i++; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif($c1 >= "\xe0" & $c1 <= "\xef"){ //looks like 3 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3; + $i = $i + 2; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } elseif($c1 >= "\xf0" & $c1 <= "\xf7"){ //looks like 4 bytes UTF8 + if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf"){ //yeah, almost sure it's UTF8 already + $buf .= $c1 . $c2 . $c3 . $c4; + $i = $i + 3; + } else { //not valid UTF8. Convert it. + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = ($c1 & "\x3f") | "\x80"; + $buf .= $cc1 . $cc2; + } + } else { //doesn't look like UTF8, but should be converted + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } elseif(($c1 & "\xc0") == "\x80"){ // needs conversion + if(isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases + $buf .= self::$win1252ToUtf8[ord($c1)]; + } else { + $cc1 = (chr(ord($c1) / 64) | "\xc0"); + $cc2 = (($c1 & "\x3f") | "\x80"); + $buf .= $cc1 . $cc2; + } + } else { // it doesn't need conversion + $buf .= $c1; + } + } + return $buf; + } else { + return $text; + } + } + static function toWin1252($text, $option = self::WITHOUT_ICONV) { + if(is_array($text)) { + foreach($text as $k => $v) { + $text[$k] = self::toWin1252($v, $option); + } + return $text; + } elseif(is_string($text)) { + return static::utf8_decode($text, $option); + } else { + return $text; + } + } + static function toISO8859($text) { + return self::toWin1252($text); + } + static function toLatin1($text) { + return self::toWin1252($text); + } + static function fixUTF8($text, $option = self::WITHOUT_ICONV){ + if(is_array($text)) { + foreach($text as $k => $v) { + $text[$k] = self::fixUTF8($v, $option); + } + return $text; + } + $last = ""; + while($last <> $text){ + $last = $text; + $text = self::toUTF8(static::utf8_decode($text, $option)); + } + $text = self::toUTF8(static::utf8_decode($text, $option)); + return $text; + } + static function UTF8FixWin1252Chars($text){ + // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1 + // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it. + // See: http://en.wikipedia.org/wiki/Windows-1252 + return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text); + } + static function removeBOM($str=""){ + if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) { + $str=substr($str, 3); + } + return $str; + } + public static function normalizeEncoding($encodingLabel) + { + $encoding = strtoupper($encodingLabel); + $encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding); + $equivalences = array( + 'ISO88591' => 'ISO-8859-1', + 'ISO8859' => 'ISO-8859-1', + 'ISO' => 'ISO-8859-1', + 'LATIN1' => 'ISO-8859-1', + 'LATIN' => 'ISO-8859-1', + 'UTF8' => 'UTF-8', + 'UTF' => 'UTF-8', + 'WIN1252' => 'ISO-8859-1', + 'WINDOWS1252' => 'ISO-8859-1' + ); + if(empty($equivalences[$encoding])){ + return 'UTF-8'; + } + return $equivalences[$encoding]; + } + public static function encode($encodingLabel, $text) + { + $encodingLabel = self::normalizeEncoding($encodingLabel); + if($encodingLabel == 'UTF-8') return Encoding::toUTF8($text); + if($encodingLabel == 'ISO-8859-1') return Encoding::toLatin1($text); + } + protected static function utf8_decode($text, $option) + { + if ($option == self::WITHOUT_ICONV || !function_exists('iconv')) { + $o = utf8_decode( + str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text)) + ); + } else { + $o = iconv("UTF-8", "Windows-1252" . ($option == self::ICONV_TRANSLIT ? '//TRANSLIT' : ($option == self::ICONV_IGNORE ? '//IGNORE' : '')), $text); + } + return $o; + } +} \ No newline at end of file diff --git a/html/includes/footer.php b/html/includes/footer.php index be5e38c..9e3a6de 100755 --- a/html/includes/footer.php +++ b/html/includes/footer.php @@ -7,7 +7,7 @@

- UTStats Beta 4.2.8 © 2005 azazel, AnthraX and toa + UTStats Beta 4.3.0 © 2005 azazel, AnthraX and toa

diff --git a/html/includes/ftptimestamp.php b/html/includes/ftptimestamp.php index 5b6994a..c19396a 100755 --- a/html/includes/ftptimestamp.php +++ b/html/includes/ftptimestamp.php @@ -1 +1 @@ -1112804209 \ No newline at end of file +1512939605 \ No newline at end of file diff --git a/html/includes/header.php b/html/includes/header.php index c4f96a6..26fdcf3 100755 --- a/html/includes/header.php +++ b/html/includes/header.php @@ -36,12 +36,27 @@ echo' + + + + + + + + + + + diff --git a/html/includes/js/adapters/standalone-framework.js b/html/includes/js/adapters/standalone-framework.js new file mode 100644 index 0000000..d41dde7 --- /dev/null +++ b/html/includes/js/adapters/standalone-framework.js @@ -0,0 +1,18 @@ +/* + Highcharts JS v4.0.4 (2014-09-02) + + Standalone Highcharts Framework + + License: MIT License +*/ +var HighchartsAdapter=function(){function p(c){function b(b,a,d){b.removeEventListener(a,d,!1)}function d(b,a,d){d=b.HCProxiedMethods[d.toString()];b.detachEvent("on"+a,d)}function a(a,c){var f=a.HCEvents,i,g,k,j;if(a.removeEventListener)i=b;else if(a.attachEvent)i=d;else return;c?(g={},g[c]=!0):g=f;for(j in g)if(f[j])for(k=f[j].length;k--;)i(a,j,f[j][k])}c.HCExtended||Highcharts.extend(c,{HCExtended:!0,HCEvents:{},bind:function(b,a){var d=this,c=this.HCEvents,g;if(d.addEventListener)d.addEventListener(b, +a,!1);else if(d.attachEvent){g=function(b){b.target=b.srcElement||window;a.call(d,b)};if(!d.HCProxiedMethods)d.HCProxiedMethods={};d.HCProxiedMethods[a.toString()]=g;d.attachEvent("on"+b,g)}c[b]===s&&(c[b]=[]);c[b].push(a)},unbind:function(c,h){var f,i;c?(f=this.HCEvents[c]||[],h?(i=HighchartsAdapter.inArray(h,f),i>-1&&(f.splice(i,1),this.HCEvents[c]=f),this.removeEventListener?b(this,c,h):this.attachEvent&&d(this,c,h)):(a(this,c),this.HCEvents[c]=[])):(a(this),this.HCEvents={})},trigger:function(b, +a){var d=this.HCEvents[b]||[],c=d.length,g,k,j;k=function(){a.defaultPrevented=!0};for(g=0;g=a.duration+ +this.startTime){this.now=this.end;this.pos=this.state=1;this.update();b=this.options.curAnim[this.prop]=!0;for(h in a.curAnim)a.curAnim[h]!==!0&&(b=!1);b&&a.complete&&a.complete.call(e);a=!1}else e=c-this.startTime,this.state=e/a.duration,this.pos=a.easing(e,0,1,a.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update(),a=!0;return a}};this.animate=function(b,d,a){var e,h="",f,i,g;b.stopAnimation=!1;if(typeof a!=="object"||a===null)e=arguments,a={duration:e[2],easing:e[3],complete:e[4]}; +if(typeof a.duration!=="number")a.duration=400;a.easing=Math[a.easing]||Math.easeInOutSine;a.curAnim=Highcharts.extend({},d);for(g in d)i=new o(b,a,g),f=null,g==="d"?(i.paths=c.init(b,b.d,d.d),i.toD=d.d,e=0,f=1):b.attr?e=b.attr(g):(e=parseFloat(HighchartsAdapter._getStyle(b,g))||0,g!=="opacity"&&(h="px")),f||(f=d[g]),i.custom(e,f,h)}},_getStyle:function(c,b){return window.getComputedStyle(c,void 0).getPropertyValue(b)},addAnimSetter:function(c,b){n[c]=b},getScript:function(c,b){var d=l.getElementsByTagName("head")[0], +a=l.createElement("script");a.type="text/javascript";a.src=c;a.onload=b;d.appendChild(a)},inArray:function(c,b){return b.indexOf?b.indexOf(c):q.indexOf.call(b,c)},adapterRun:function(c,b){return parseInt(HighchartsAdapter._getStyle(c,b),10)},grep:func