From: Ant Zucaro Date: Sat, 16 Jun 2012 13:53:08 +0000 (-0400) Subject: Merge branch 'master' of github.com:antzucaro/XonStat X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonstat.git;a=commitdiff_plain;h=ab01b511f02a52d5386be63f228f9237b0e4586f;hp=7ceb773ef64c3bff51fc1c325e3f203c439c43fc Merge branch 'master' of github.com:antzucaro/XonStat Conflicts: xonstat/views/__init__.py xonstat/views/player.py --- diff --git a/xonstat/__init__.py b/xonstat/__init__.py old mode 100755 new mode 100644 index 79f7f52..3160b75 --- a/xonstat/__init__.py +++ b/xonstat/__init__.py @@ -2,7 +2,7 @@ import sqlahelper from pyramid.config import Configurator from sqlalchemy import engine_from_config from xonstat.models import initialize_db -from xonstat.views import * +from xonstat.views import * def main(global_config, **settings): """ This function returns a Pyramid WSGI application. @@ -20,30 +20,26 @@ def main(global_config, **settings): # ROOT ROUTE config.add_route("main_index", "/") - config.add_view(main_index, route_name="main_index", - renderer="main_index.mako") + config.add_view(main_index, route_name="main_index", renderer="main_index.mako") # MAIN SUBMISSION ROUTE config.add_route("stats_submit", "stats/submit") config.add_view(stats_submit, route_name="stats_submit") # PLAYER ROUTES - config.add_route("player_game_index", - "/player/{player_id:\d+}/games") - config.add_view(player_game_index, route_name="player_game_index", - renderer="player_game_index.mako") + config.add_route("player_game_index", "/player/{player_id:\d+}/games") + config.add_view(player_game_index, route_name="player_game_index", renderer="player_game_index.mako") config.add_route("player_index", "/players") - config.add_view(player_index, route_name="player_index", - renderer="player_index.mako") + config.add_view(player_index, route_name="player_index", renderer="player_index.mako") config.add_route("player_info", "/player/{id:\d+}") - config.add_view(player_info, route_name="player_info", - renderer="player_info.mako") + config.add_view(player_info, route_name="player_info", renderer="player_info.mako") - config.add_route("player_accuracy", "/player/{id:\d+}/accuracy") - config.add_view(player_accuracy_json, route_name="player_accuracy", - renderer="json") + config.add_route("player_accuracy", "/player/{id:\d+}/accuracy") + config.add_route("player_accuracy_json", "/player/{id:\d+}/accuracy.json") + config.add_view(player_accuracy_json, route_name="player_accuracy", renderer="json") + config.add_view(player_accuracy_json, route_name="player_accuracy_json", renderer="json") config.add_route("player_damage", "/player/{id:\d+}/damage") config.add_view(player_damage_json, route_name="player_damage", @@ -51,47 +47,35 @@ def main(global_config, **settings): # GAME ROUTES config.add_route("game_index", "/games") - config.add_view(game_index, route_name="game_index", - renderer="game_index.mako") + config.add_view(game_index, route_name="game_index", renderer="game_index.mako") config.add_route("game_info", "/game/{id:\d+}") - config.add_view(game_info, route_name="game_info", - renderer="game_info.mako") + config.add_view(game_info, route_name="game_info", renderer="game_info.mako") config.add_route("rank_index", "/ranks/{game_type_cd:ctf|dm|tdm|duel}") - config.add_view(rank_index, route_name="rank_index", - renderer="rank_index.mako") + config.add_view(rank_index, route_name="rank_index", renderer="rank_index.mako") # SERVER ROUTES config.add_route("server_index", "/servers") - config.add_view(server_index, route_name="server_index", - renderer="server_index.mako") + config.add_view(server_index, route_name="server_index", renderer="server_index.mako") - config.add_route("server_game_index", - "/server/{server_id:\d+}/games/page/{page:\d+}") - config.add_view(server_game_index, route_name="server_game_index", - renderer="server_game_index.mako") + config.add_route("server_game_index", "/server/{server_id:\d+}/games/page/{page:\d+}") + config.add_view(server_game_index, route_name="server_game_index", renderer="server_game_index.mako") config.add_route("server_info", "/server/{id:\d+}") - config.add_view(server_info, route_name="server_info", - renderer="server_info.mako") + config.add_view(server_info, route_name="server_info", renderer="server_info.mako") # MAP ROUTES + config.add_route("map_index", "/maps") config.add_route("map_index_json", "/maps.json") - config.add_view(map_index_json, route_name="map_index_json", - renderer="json") - - config.add_route("map_index", "/maps") - config.add_view(map_index, route_name="map_index", - renderer="map_index.mako") + config.add_view(map_index, route_name="map_index", renderer="map_index.mako") + config.add_view(map_index_json, route_name="map_index_json", renderer="json") config.add_route("map_info", "/map/{id:\d+}") - config.add_view(map_info, route_name="map_info", - renderer="map_info.mako") + config.add_view(map_info, route_name="map_info", renderer="map_info.mako") # SEARCH ROUTES config.add_route("search", "search") - config.add_view(search, route_name="search", - renderer="search.mako") + config.add_view(search, route_name="search", renderer="search.mako") return config.make_wsgi_app() diff --git a/xonstat/elo.py b/xonstat/elo.py old mode 100755 new mode 100644 index 9d1d467..19bcfba --- a/xonstat/elo.py +++ b/xonstat/elo.py @@ -1,46 +1,46 @@ -import sys -import math -import random - -class EloParms: - def __init__(self, global_K = 15, initial = 100, floor = 100, logdistancefactor = math.log(10)/float(400), maxlogdistance = math.log(10)): - self.global_K = global_K - self.initial = initial - self.floor = floor - self.logdistancefactor = logdistancefactor - self.maxlogdistance = maxlogdistance - - -class KReduction: - def __init__(self, fulltime, mintime, minratio, games_min, games_max, games_factor): - self.fulltime = fulltime - self.mintime = mintime - self.minratio = minratio - self.games_min = games_min - self.games_max = games_max - self.games_factor = games_factor - - def eval(self, mygames, mytime, matchtime): - if mytime < self.mintime: - return 0 - if mytime < self.minratio * matchtime: - return 0 - if mytime < self.fulltime: - k = mytime / float(self.fulltime) - else: - k = 1.0 - if mygames >= self.games_max: - k *= self.games_factor - elif mygames > self.games_min: - k *= 1.0 - (1.0 - self.games_factor) * (mygames - self.games_min) / float(self.games_max - self.games_min) - return k - - -# parameters for K reduction -# this may be touched even if the DB already exists -KREDUCTION = KReduction(600, 120, 0.5, 0, 32, 0.2) - -# parameters for chess elo -# only global_K may be touched even if the DB already exists -# we start at K=200, and fall to K=40 over the first 20 games -ELOPARMS = EloParms(global_K = 200) +import sys +import math +import random + +class EloParms: + def __init__(self, global_K = 15, initial = 100, floor = 100, logdistancefactor = math.log(10)/float(400), maxlogdistance = math.log(10)): + self.global_K = global_K + self.initial = initial + self.floor = floor + self.logdistancefactor = logdistancefactor + self.maxlogdistance = maxlogdistance + + +class KReduction: + def __init__(self, fulltime, mintime, minratio, games_min, games_max, games_factor): + self.fulltime = fulltime + self.mintime = mintime + self.minratio = minratio + self.games_min = games_min + self.games_max = games_max + self.games_factor = games_factor + + def eval(self, mygames, mytime, matchtime): + if mytime < self.mintime: + return 0 + if mytime < self.minratio * matchtime: + return 0 + if mytime < self.fulltime: + k = mytime / float(self.fulltime) + else: + k = 1.0 + if mygames >= self.games_max: + k *= self.games_factor + elif mygames > self.games_min: + k *= 1.0 - (1.0 - self.games_factor) * (mygames - self.games_min) / float(self.games_max - self.games_min) + return k + + +# parameters for K reduction +# this may be touched even if the DB already exists +KREDUCTION = KReduction(600, 120, 0.5, 0, 32, 0.2) + +# parameters for chess elo +# only global_K may be touched even if the DB already exists +# we start at K=200, and fall to K=40 over the first 20 games +ELOPARMS = EloParms(global_K = 200) diff --git a/xonstat/models.py b/xonstat/models.py old mode 100755 new mode 100644 index d5cd885..949f90c --- a/xonstat/models.py +++ b/xonstat/models.py @@ -34,20 +34,17 @@ class Player(object): return pretty_date(self.create_dt) def __repr__(self): - return "" % (self.player_id, - self.nick.encode('utf-8')) + return "" % (self.player_id, self.nick.encode('utf-8')) class GameType(object): def __repr__(self): - return "" % (self.game_type_cd, self.descr, - self.active_ind) + return "" % (self.game_type_cd, self.descr, self.active_ind) class Weapon(object): def __repr__(self): - return "" % (self.weapon_cd, self.descr, - self.active_ind) + return "" % (self.weapon_cd, self.descr, self.active_ind) class Server(object): @@ -82,8 +79,7 @@ class Game(object): self.winner = winner def __repr__(self): - return "" % (self.game_id, self.start_dt, - self.game_type_cd, self.server_id) + return "" % (self.game_id, self.start_dt, self.game_type_cd, self.server_id) def fuzzy_date(self): return pretty_date(self.start_dt) @@ -201,8 +197,7 @@ class PlayerGameStat(object): self.create_dt = create_dt def __repr__(self): - return "" \ - % (self.player_id, self.game_id, self.create_dt) + return "" % (self.player_id, self.game_id, self.create_dt) def nick_stripped(self): if self.nick is None: @@ -231,8 +226,7 @@ class PlayerGameStat(object): class Achievement(object): def __repr__(self): - return "" % (self.achievement_cd, self.descr, - self.limit) + return "" % (self.achievement_cd, self.descr, self.limit) class PlayerAchievement(object): @@ -242,8 +236,7 @@ class PlayerAchievement(object): class PlayerWeaponStat(object): def __repr__(self): - return "" % (self.player_weapon_stats_id, - self.player_id, self.game_id) + return "" % (self.player_weapon_stats_id, self.player_id, self.game_id) class Hashkey(object): @@ -270,8 +263,7 @@ class PlayerElo(object): self.elo = ELOPARMS.initial def __repr__(self): - return "" % \ - (self.player_id, self.game_type_cd, self.elo) + return "" % (self.player_id, self.game_type_cd, self.elo) class PlayerRank(object): @@ -284,8 +276,7 @@ class PlayerRank(object): def __repr__(self): - return "" % \ - (self.player_id, self.game_type_cd, self.rank) + return "" % (self.player_id, self.game_type_cd, self.rank) def initialize_db(engine=None): diff --git a/xonstat/static/css/colorbox.css b/xonstat/static/css/colorbox.css index e0ac646..8358ac5 100755 --- a/xonstat/static/css/colorbox.css +++ b/xonstat/static/css/colorbox.css @@ -1,49 +1,49 @@ -/* - ColorBox Core Style: - The following CSS is consistent between example themes and should not be altered. -*/ -#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} -#cboxOverlay{position:fixed; width:100%; height:100%;} -#cboxMiddleLeft, #cboxBottomLeft{clear:left;} -#cboxContent{position:relative;} -#cboxLoadedContent{overflow:auto;} -#cboxTitle{margin:0;} -#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%;} -#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} -.cboxPhoto{float:left; margin:auto; border:0; display:block;} -.cboxIframe{width:100%; height:100%; display:block; border:0;} - -/* - User Style: - Change the following styles to modify the appearance of ColorBox. They are - ordered & tabbed in a way that represents the nesting of the generated HTML. -*/ -#cboxOverlay{background:#000;} -#colorbox{} - #cboxTopLeft{width:14px; height:14px; background:url(/static/images/controls.png) no-repeat 0 0;} - #cboxTopCenter{height:14px; background:url(/static/images/border.png) repeat-x top left;} - #cboxTopRight{width:14px; height:14px; background:url(/static/images/controls.png) no-repeat -36px 0;} - #cboxBottomLeft{width:14px; height:43px; background:url(/static/images/controls.png) no-repeat 0 -32px;} - #cboxBottomCenter{height:43px; background:url(/static/images/border.png) repeat-x bottom left;} - #cboxBottomRight{width:14px; height:43px; background:url(/static/images/controls.png) no-repeat -36px -32px;} - #cboxMiddleLeft{width:14px; background:url(/static/images/controls.png) repeat-y -175px 0;} - #cboxMiddleRight{width:14px; background:url(/static/images/controls.png) repeat-y -211px 0;} - #cboxContent{background:#fff; overflow:visible;} - #cboxLoadedContent{margin-bottom:5px;} - #cboxLoadingOverlay{background:url(/static/images/loading_background.png) no-repeat center center;} - #cboxLoadingGraphic{background:url(/static/images/loading.gif) no-repeat center center;} - #cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;} - #cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;} - - #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{position:absolute; bottom:-29px; background:url(/static/images/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;} - #cboxPrevious{left:0px; background-position: -51px -25px;} - #cboxPrevious.hover{background-position:-51px 0px;} - #cboxNext{left:27px; background-position:-75px -25px;} - #cboxNext.hover{background-position:-75px 0px;} - #cboxClose{right:0; background-position:-100px -25px;} - #cboxClose.hover{background-position:-100px 0px;} - - .cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;} - .cboxSlideshow_on #cboxSlideshow.hover{background-position:-150px 0px;} - .cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;} - .cboxSlideshow_off #cboxSlideshow.hover{background-position:-125px 0px;} +/* + ColorBox Core Style: + The following CSS is consistent between example themes and should not be altered. +*/ +#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} +#cboxOverlay{position:fixed; width:100%; height:100%;} +#cboxMiddleLeft, #cboxBottomLeft{clear:left;} +#cboxContent{position:relative;} +#cboxLoadedContent{overflow:auto;} +#cboxTitle{margin:0;} +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%;} +#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} +.cboxPhoto{float:left; margin:auto; border:0; display:block;} +.cboxIframe{width:100%; height:100%; display:block; border:0;} + +/* + User Style: + Change the following styles to modify the appearance of ColorBox. They are + ordered & tabbed in a way that represents the nesting of the generated HTML. +*/ +#cboxOverlay{background:#000;} +#colorbox{} + #cboxTopLeft{width:14px; height:14px; background:url(/static/images/controls.png) no-repeat 0 0;} + #cboxTopCenter{height:14px; background:url(/static/images/border.png) repeat-x top left;} + #cboxTopRight{width:14px; height:14px; background:url(/static/images/controls.png) no-repeat -36px 0;} + #cboxBottomLeft{width:14px; height:43px; background:url(/static/images/controls.png) no-repeat 0 -32px;} + #cboxBottomCenter{height:43px; background:url(/static/images/border.png) repeat-x bottom left;} + #cboxBottomRight{width:14px; height:43px; background:url(/static/images/controls.png) no-repeat -36px -32px;} + #cboxMiddleLeft{width:14px; background:url(/static/images/controls.png) repeat-y -175px 0;} + #cboxMiddleRight{width:14px; background:url(/static/images/controls.png) repeat-y -211px 0;} + #cboxContent{background:#fff; overflow:visible;} + #cboxLoadedContent{margin-bottom:5px;} + #cboxLoadingOverlay{background:url(/static/images/loading_background.png) no-repeat center center;} + #cboxLoadingGraphic{background:url(/static/images/loading.gif) no-repeat center center;} + #cboxTitle{position:absolute; bottom:-25px; left:0; text-align:center; width:100%; font-weight:bold; color:#7C7C7C;} + #cboxCurrent{position:absolute; bottom:-25px; left:58px; font-weight:bold; color:#7C7C7C;} + + #cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{position:absolute; bottom:-29px; background:url(/static/images/controls.png) no-repeat 0px 0px; width:23px; height:23px; text-indent:-9999px;} + #cboxPrevious{left:0px; background-position: -51px -25px;} + #cboxPrevious.hover{background-position:-51px 0px;} + #cboxNext{left:27px; background-position:-75px -25px;} + #cboxNext.hover{background-position:-75px 0px;} + #cboxClose{right:0; background-position:-100px -25px;} + #cboxClose.hover{background-position:-100px 0px;} + + .cboxSlideshow_on #cboxSlideshow{background-position:-125px 0px; right:27px;} + .cboxSlideshow_on #cboxSlideshow.hover{background-position:-150px 0px;} + .cboxSlideshow_off #cboxSlideshow{background-position:-150px -25px; right:27px;} + .cboxSlideshow_off #cboxSlideshow.hover{background-position:-125px 0px;} diff --git a/xonstat/static/js/jquery.colorbox-min.js b/xonstat/static/js/jquery.colorbox-min.js old mode 100755 new mode 100644 index b5f6e83..689a007 --- a/xonstat/static/js/jquery.colorbox-min.js +++ b/xonstat/static/js/jquery.colorbox-min.js @@ -1,4 +1,4 @@ -// ColorBox v1.3.17.1 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+ -// Copyright (c) 2011 Jack Moore - jack@colorpowered.com -// Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php +// ColorBox v1.3.17.1 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+ +// Copyright (c) 2011 Jack Moore - jack@colorpowered.com +// Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php (function(a,b,c){function bc(b){if(!T){O=b,_(a.extend(J,a.data(O,e))),x=a(O),P=0,J.rel!=="nofollow"&&(x=a("."+X).filter(function(){var b=a.data(this,e).rel||this.rel;return b===J.rel}),P=x.index(O),P===-1&&(x=x.add(O),P=x.length-1));if(!R){R=S=!0,q.show();if(J.returnFocus)try{O.blur(),a(O).one(k,function(){try{this.focus()}catch(a){}})}catch(c){}p.css({opacity:+J.opacity,cursor:J.overlayClose?"pointer":"auto"}).show(),J.w=Z(J.initialWidth,"x"),J.h=Z(J.initialHeight,"y"),W.position(0),n&&y.bind("resize."+o+" scroll."+o,function(){p.css({width:y.width(),height:y.height(),top:y.scrollTop(),left:y.scrollLeft()})}).trigger("resize."+o),ba(g,J.onOpen),I.add(C).hide(),H.html(J.close).show()}W.load(!0)}}function bb(){var a,b=f+"Slideshow_",c="click."+f,d,e,g;J.slideshow&&x[1]?(d=function(){E.text(J.slideshowStop).unbind(c).bind(i,function(){if(P"),b.open=!0;f.each(function(){a.data(this,e,a.extend({},a.data(this,e)||d,b)),a(this).addClass(X)}),g=b.open,a.isFunction(g)&&(g=g.call(f)),g&&bc(f[0]);return f},W.init=function(){y=a(c),q=Y().attr({id:e,"class":m?f+(n?"IE6":"IE"):""}),p=Y("Overlay",n?"position:absolute":"").hide(),r=Y("Wrapper"),s=Y("Content").append(z=Y("LoadedContent","width:0; height:0; overflow:hidden"),B=Y("LoadingOverlay").add(Y("LoadingGraphic")),C=Y("Title"),D=Y("Current"),F=Y("Next"),G=Y("Previous"),E=Y("Slideshow").bind(g,bb),H=Y("Close")),r.append(Y().append(Y("TopLeft"),t=Y("TopCenter"),Y("TopRight")),Y(!1,"clear:left").append(u=Y("MiddleLeft"),s,v=Y("MiddleRight")),Y(!1,"clear:left").append(Y("BottomLeft"),w=Y("BottomCenter"),Y("BottomRight"))).children().children().css({"float":"left"}),A=Y(!1,"position:absolute; width:9999px; visibility:hidden; display:none"),a("body").prepend(p,q.append(r,A)),s.children().hover(function(){a(this).addClass("hover")},function(){a(this).removeClass("hover")}).addClass("hover"),K=t.height()+w.height()+s.outerHeight(!0)-s.height(),L=u.width()+v.width()+s.outerWidth(!0)-s.width(),M=z.outerHeight(!0),N=z.outerWidth(!0),q.css({"padding-bottom":K,"padding-right":L}).hide(),F.click(function(){W.next()}),G.click(function(){W.prev()}),H.click(function(){W.close()}),I=F.add(G).add(D).add(E),s.children().removeClass("hover"),p.click(function(){J.overlayClose&&W.close()}),a(b).bind("keydown."+f,function(a){var b=a.keyCode;R&&J.escKey&&b===27&&(a.preventDefault(),W.close()),R&&J.arrowKey&&x[1]&&(b===37?(a.preventDefault(),G.click()):b===39&&(a.preventDefault(),F.click()))})},W.remove=function(){q.add(p).remove(),a("."+X).removeData(e).removeClass(X)},W.position=function(a,c){function g(a){t[0].style.width=w[0].style.width=s[0].style.width=a.style.width,B[0].style.height=B[1].style.height=s[0].style.height=u[0].style.height=v[0].style.height=a.style.height}var d,e=0,f=0;q.hide(),J.fixed&&!n?q.css({position:"fixed"}):(e=y.scrollTop(),f=y.scrollLeft(),q.css({position:"absolute"})),J.right!==!1?f+=Math.max(y.width()-J.w-N-L-Z(J.right,"x"),0):J.left!==!1?f+=Z(J.left,"x"):f+=Math.max(y.width()-J.w-N-L,0)/2,J.bottom!==!1?e+=Math.max(b.documentElement.clientHeight-J.h-M-K-Z(J.bottom,"y"),0):J.top!==!1?e+=Z(J.top,"y"):e+=Math.max(b.documentElement.clientHeight-J.h-M-K,0)/2,q.show(),d=q.width()===J.w+N&&q.height()===J.h+M?0:a,r[0].style.width=r[0].style.height="9999px",q.dequeue().animate({width:J.w+N,height:J.h+M,top:e,left:f},{duration:d,complete:function(){g(this),S=!1,r[0].style.width=J.w+N+L+"px",r[0].style.height=J.h+M+K+"px",c&&c()},step:function(){g(this)}})},W.resize=function(a){if(R){a=a||{},a.width&&(J.w=Z(a.width,"x")-N-L),a.innerWidth&&(J.w=Z(a.innerWidth,"x")),z.css({width:J.w}),a.height&&(J.h=Z(a.height,"y")-M-K),a.innerHeight&&(J.h=Z(a.innerHeight,"y"));if(!a.innerHeight&&!a.height){var b=z.wrapInner("
").children();J.h=b.height(),b.replaceWith(b.children())}z.css({height:J.h}),W.position(J.transition==="none"?0:J.speed)}},W.prep=function(b){function h(b){W.position(b,function(){function o(){m&&q[0].style.removeAttribute("filter")}var b,d,g,h,j=x.length,k,n;!R||(n=function(){clearTimeout(V),B.hide(),ba(i,J.onComplete)},m&&Q&&z.fadeIn(100),C.html(J.title).add(z).show(),j>1?(typeof J.current=="string"&&D.html(J.current.replace(/\{current\}/,P+1).replace(/\{total\}/,j)).show(),F[J.loop||P")[0].src=h),$(d)&&(a("")[0].src=d))):I.hide(),J.iframe?(k=a("