コード例 #1
0
ファイル: admin.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        account = accounts.account()
        if not account or not account.ADMIN_LINK_ACCESS_RIGHT:
            self.redirect(users.create_login_url(self.request.uri))
            return
        self.player_name = self.request.get('p').lower()

        # Show admin UI
        template_values = {
            'tabs': config.get_tabs(self.player_name, account),
            'selected_tab': config.TAB_NONE,
            'account': account,
            'adminlog_url': self.get_url(config.ADMINLOG_URL),
            'playerdetail_url': self.get_url(config.PLAYERDETAIL_URL),
            'adjust_score_url': self.get_url(config.ADJUSTSCORE_URL),
            'blockplayer_url': self.get_url(config.BLOCKPLAYER_URL),
            'hideplayer_url': self.get_url(config.HIDEPLAYER_URL),
            'resetplayer_url': self.get_url(config.RESETPLAYER_URL),
            'sendchat_url': self.get_url(config.SENDCHAT_URL),
            'drain_url': self.get_url(config.DRAIN_URL),
            'logout_url': users.create_logout_url(self.request.uri),
        }

        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'admin.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #2
0
ファイル: command.py プロジェクト: Ahmar/hostile-takeover
 def get_template_values(self):
     template_values = {
         'tabs': config.get_tabs(''),
         'selected_tab': config.TAB_NONE,
         'serverinfos': self.get_serverinfos(),
         'refresh_url': self.request.uri,
         'admin_url': config.ADMIN_URL,
         'logout_url': users.create_logout_url(config.ADMIN_URL),
     }
     return template_values
コード例 #3
0
ファイル: resetplayer.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        if not users.is_current_user_admin():
            self.redirect(users.create_logout_url(config.ADMIN_URL))
            return

        template_values = {
            'tabs': config.get_tabs(''),
            'selected_tab': config.TAB_NONE,
        }

        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'resetplayer.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #4
0
ファイル: hideplayer.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        account = self.has_access()
        if not account:
            self.redirect(users.create_login_url(self.request.uri))
            return
        player_name = self.request.get('p').lower()

        template_values = {
            'tabs': config.get_tabs(player_name, account),
            'selected_tab': config.TAB_NONE,
        }

        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'hideplayer.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #5
0
ファイル: about.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # Get player name, if any
        player_name = self.request.get('p')

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_ABOUT,
        }

        #self.set_caching_headers(MAX_AGE_SECONDS)
        #self.response.headers['Content-Type'] = 'text/plain'
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'about.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #6
0
ファイル: message.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # Get player name, if any
        player_name = self.request.get('p')
        # Get message id, if any
        id = int(self.request.get('id'))

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_NONE,
            'id': id,
        }

        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'message.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #7
0
ファイル: search.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # Get player name, if any
        player_name = self.request.get('p')

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_SEARCH,
            'player_name': player_name,
            'games_url': config.GAMES_URL,
        }

        self.set_caching_headers(MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'search.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #8
0
ファイル: adminlog.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # Requires an authenticated user with proper access rights
        account = accounts.account()
        if not account or not account.ADMIN_LOG_ACCESS_RIGHT:
            self.redirect(users.create_logout_url(self.request.uri))

        # Get args
        self.get_args()

        # If json request, perform that response
        if self.request.get('j'):
            self.response.headers['Content-Type'] = 'text/plain'
            data = dict(tables=self.collect_tables())
            self.response.out.write(json.dumps(data))
            return

        # Calc all-url
        if self.player_name:
            all_url = '%s?p=%s&c=%d' % (config.ADMINLOG_URL, self.player_name, self.count)
        else:
            all_url = '%s?c=%d' % (config.ADMINLOG_URL, self.count)

        # Calc count-url
        if self.player_name:
            count_url = '%s?p=%s' % (config.ADMINLOG_URL, self.player_name)
        else:
            count_url = '%s?x=1' % config.ADMINLOG_URL

        # Otherwise render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(self.player_name, account),
            'selected_tab': config.TAB_NONE,
            'all_url': all_url,
            'count_url': count_url,
            'tables': self.collect_tables(),
            'player_name': self.player_name,
            'count': self.count,
            'show_counts': [ 50, 100, 250, 500, 1000 ],
        }

        self.set_caching_headers(60)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'adminlog.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #9
0
ファイル: stats.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # player_name is the player that is browsing. The tabs will be
        # populated with query args with this player name
        player_name = self.request.get('p')

        # stats_player is the player to get stats on. If 'u' isn't set,
        # use player_name.
        stats_player = self.request.get('u')
        if stats_player == '':
            stats_player = player_name
        
        p = player.load_from_name(stats_player, player_name)
        if not p:
            message.show(self, message.PLAYER_NOT_FOUND)
            return

        selected_tab = config.TAB_NONE
        if p.is_viewer_also_player():
            selected_tab = config.TAB_STATS

        # get player detail url
        detail_url = ''
        account = accounts.account()
        if account and account.SEE_PLAYER_INFO_ACCESS_RIGHT:
            if player_name:
                detail_url = '%s?p=%s&q=%s' % (config.PLAYERDETAIL_URL, player_name, stats_player)
            else:
                detail_url = '%s?q=%s' % (config.PLAYERDETAIL_URL, stats_player)

        # Fill in the template
        template_values = {
            'tabs': config.get_tabs(player_name, account),
            'selected_tab': selected_tab,
            'player': p,
            'player_default_rating': gamestats.PLAYER_DEFAULT_RATING,
            'detail_url': detail_url
        }

        self.set_caching_headers(config.INFOPAGE_MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'stats.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #10
0
ファイル: adjustscore.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        account = self.has_access()
        if not account:
            self.redirect(users.create_login_url(self.request.uri))
            return
        type = self.request.get('t').lower()
        u = self.request.get('u').lower()
        player_name = self.request.get('p').lower()
        message = ''

        # if no type specified, there is no query
        rating = 0
        next_type = ''
        if not type:
            # The next request will be a query for a player name's score
            next_type = 'q'

        # Validate the user. Is this a query or set score request?
        p = None
        if type == 'q' or type == 's':
            # This is a query for a user. Make sure the user is valid
            if not u:
                message = 'No player name entered!'
                type = ''
                next_type = 'q'
            else:
                p = models.PlayerModel.get(models.playermodel_key(u))
                if not p:
                    message = 'Could not find player %s! Please try again:' % u
                    u = ''
                    type = ''
                    next_type = 'q'

        # Step through the states
        rating = 0
        reason = ''
        if type == 'q':
            # The next request will be for changing a score
            next_type = 's'
            rating = p.rating

        if type == 's':
            # Is the new rating valid?
            rating = self.request.get('s')
            reason = self.request.get('r')
            success = True
            try:
                rating = int(rating)
            except:
                success = False
                
            if not success or rating >= 3000 or rating < 0:
                message = '"%s" is an invalid score. Please try again:' % rating
                rating = p.rating
                type = 'q'
                next_type = 's'

            elif not reason:
                message = 'Must enter a reason. Please try again:'
                rating = p.rating
                type = 'q'
                next_type = 's'

            else:
                # Record this action
                d = dict(action='adjust_score', player_name=u, old_rating=p.rating, new_rating=rating, reason=reason)
                admin.save_action(account.name, self.request.remote_addr, d)

                p.rating = rating
                p.put()
                message = 'Successfully set the score of player %s to %s, reason: %s.' % (u, rating, reason)
                type = ''
                next_type = 'q'

        template_values = {
            'tabs': config.get_tabs(player_name, account),
            'selected_tab': config.TAB_NONE,
            'form_url': config.ADJUSTSCORE_URL,
            'message': message,
            'player_name': player_name,
            'u': u,
            'rating': rating,
            'type': type,
            'reason': reason,
            'next_type': next_type
        }

        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'adjustscore.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #11
0
    def get(self):
        # Save this action
        self.save_action()

        # Get player name, if any
        player_name = self.request.get('p')

        # Get the row count and validate
        count_str = self.request.get('count')
        if count_str == '':
            count = 25
        else:
            count = int(count_str)
            if count < 0:
                count = 0
            if count > SHOW_COUNT_MAX:
                count = SHOW_COUNT_MAX 

        # Get row data

        q = models.PlayerModel.all()
        q.filter('blocked =', False)
        q.filter('hidden =', False)
        q.order('-rating')
        results = q.fetch(count)
        players = [player.Player(p, player_name) for p in results]

        # Get game data with one call
        game_keys = []
        for p in players:
            if p.last_game_key_name:
                key_name = p.last_game_key_name
                key = models.gamestatsmodel_key_from_name(key_name)
                game_keys.append(key)
        game_objs = models.GameStatsModel.get(game_keys)
        game_map = {}
        for game_obj in game_objs:
            game_map[game_obj.key().name()] = game_obj

        rows = []
        for index in xrange(len(players)):
            p =  players[index]
            if p.rating == 0:
                break
            row = {}
            row['profile_url'] = p.get_player_stats_url()
            row['rank'] = index + 1
            row['name'] = p.name
            row['avatar_url'] = p.get_avatar_url()
            row['game_count'] = p.game_count
            if game_map.has_key(p.last_game_key_name):
                title = game_map[p.last_game_key_name].mission_title
                row['last_mission_name'] = title
            else:
                row['last_mission_name'] = None
            row['player_rating'] = p.rating
            rows.append(row)

        # Figure out the next show url, if any (Show top N)
        show_count = count + SHOW_COUNT_INCREMENT
        if show_count > SHOW_COUNT_MAX:
            show_count = SHOW_COUNT_MAX
        show_url = ''
        if len(rows) == count and show_count > count:
            show_url = '%s?count=%d' % (config.LEADERBOARD_URL, show_count)
            if player_name != '':
                show_url = '%s&p=%s' % (show_url, player_name)

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_LEADERBOARD,
            'rows': rows,
            'chevron_image_url': config.CHEVRON_IMAGE_URL,
            'show_count' : show_count,
            'show_url' : show_url,
        }
        
        self.set_caching_headers(config.INFOPAGE_MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'leaderboard.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #12
0
    def get(self):
        # Requires an authenticated user with proper access rights
        account = accounts.account()
        if not account or not account.SEE_PLAYER_INFO_ACCESS_RIGHT:
            self.redirect(users.create_logout_url(self.request.uri))

        # Get args
        self.get_args()

        # Query for results
        keys = []
        if self.user_name:
            keys.append('player: %s' % self.user_name)
        if self.did:
            keys.append('did: %s' % self.did)
        if self.ip_address:
            keys.append('ip: %s' % self.ip_address)
        if len(keys) != 0:
            query_string = '%s' % ', '.join(keys)
        else:
            query_string = 'all'

        # If json request, perform that response
        if self.request.get('j'):
            self.response.headers['Content-Type'] = 'text/plain'
            data = dict(query_string=query_string,tables=self.collect_tables())
            self.response.out.write(json.dumps(data))
            return

        # Calc all-url
        if self.player_name:
            all_url = '%s?p=%s&c=%d' % (config.PLAYERDETAIL_URL, self.player_name, self.count)
        else:
            all_url = '%s?c=%d' % (config.PLAYERDETAIL_URL, self.count)

        # Calc count-url
        if self.player_name:
            if self.q:
                count_url = '%s?p=%s&q=%s' % (config.PLAYERDETAIL_URL, self.player_name, self.q)
            else:
                count_url = '%s?p=%s' % (config.PLAYERDETAIL_URL, self.player_name)
        else:
            if self.q:
                count_url = '%s?q=%s' % (config.PLAYERDETAIL_URL, self.q)
            else:
                count_url = '%s?x=1' % config.PLAYERDETAIL_URL

        # Otherwise render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(self.player_name, account),
            'selected_tab': config.TAB_NONE,
            'query_string': query_string,
            'show_all': query_string != 'all',
            'all_url': all_url,
            'count_url': count_url,
            'tables': self.collect_tables(),
            'player_name': self.player_name,
            'count': self.count,
            'show_counts': [ 50, 100, 250, 500, 1000 ],
        }

        self.set_caching_headers(60)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'playerdetail.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #13
0
ファイル: gamedetail.py プロジェクト: Ahmar/hostile-takeover
    def get(self):
        # If a game key is specified, use that. If no game key and a player
        # is specified, use the last game of that player. If neither, show
        # a message to the user. The common error case is a non-logged in
        # player, who hasn't specified a game.

        # Get player name, if any
        player_name = self.request.get('p')

        # Get game key. If missing, get it from the player's last game
        key_name = self.request.get('g')
        if key_name == '':
            # No game key name. Is there a player?
            if player_name == '':
                message.show(self, message.GAME_NOT_FOUND)
                return
            obj = models.PlayerModel.get(models.playermodel_key(player_name))
            if not obj:
                message.show(self, message.PLAYER_NOT_FOUND)
                return
            key_name = obj.last_game_key_name
            if key_name == '':
                message.show(self, message.PLAYER_NOT_PLAYED_GAME)
                return
        g, game_obj = gamestats.load_from_key_name(key_name, player_name,
                load_players=True)
        if not g:
            message.show(self, message.GAME_NOT_FOUND)
            return

        if self.request.get('j') == '1':
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.out.write(g.json)
            return

        if self.request.get('i') == '1':
            self.response.headers['Content-Type'] = 'text/plain'
            for player_stat in g.player_stats:
                ip = 'unknown'
                if 'ip' in player_stat.__dict__ and len(player_stat.ip) != 0:
                    ip = player_stat.ip
                did = 'unknown'
                if 'did' in player_stat.__dict__ and len(player_stat.did) != 0:
                    did = player_stat.did
                winner = ''
                if player_stat.win_result == gamestats.PLAYER_RESULT_WIN:
                    winner = ' (winner)'
                self.response.out.write('Player: %s ip: %s did: %s %s\n' % (player_stat.name, ip, did, winner))
            if game_obj.dids:
                self.response.out.write('\n')
                self.response.out.write(game_obj.dids)
            return

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_NONE,
            'gamestats': g,
            'units_built_sums': self.get_units_built_sums(g),
            'computer_default_rating': gamestats.COMPUTER_DEFAULT_RATING,
            'anonymous_default_rating': gamestats.ANONYMOUS_DEFAULT_RATING,
            'player_default_rating': gamestats.PLAYER_DEFAULT_RATING,
            'computer_avatar_url': config.COMPUTER_AVATAR_URL,
            'anonymous_avatar_url': config.ANONYMOUS_AVATAR_URL,
            'winner_image_url': config.WINNER_IMAGE_URL,
            'chevron_image_url': config.CHEVRON_IMAGE_URL,
        }

        self.set_caching_headers(config.INFOPAGE_MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'gamedetail.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #14
0
    def get(self):
        # Save this action
        self.save_action()

        # Get player name, if any
        player_name = self.request.get('p')

        # Get the row count and validate
        count_str = self.request.get('count')
        if count_str == '':
            count = 25
        else:
            count = int(count_str)
            if count < 0:
                count = 0
            if count > SHOW_COUNT_MAX:
                count = SHOW_COUNT_MAX 

        # Get row data

        q = models.PlayerModel.all()
        q.filter('blocked =', False)
        q.filter('hidden =', False)
        q.order('-rating')
        results = q.fetch(count)
        players = [player.Player(p, player_name) for p in results]

        # Get game data with one call
        game_keys = []
        for p in players:
            if p.last_game_key_name:
                key_name = p.last_game_key_name
                key = models.gamestatsmodel_key_from_name(key_name)
                game_keys.append(key)
        game_objs = models.GameStatsModel.get(game_keys)
        game_map = {}
        for game_obj in game_objs:
            game_map[game_obj.key().name()] = game_obj

        rows = []
        for index in xrange(len(players)):
            p =  players[index]
            if p.rating == 0:
                break
            row = {}
            row['profile_url'] = p.get_player_stats_url()
            row['rank'] = index + 1
            row['name'] = p.name
            row['avatar_url'] = p.get_avatar_url()
            row['game_count'] = p.game_count
            if game_map.has_key(p.last_game_key_name):
                title = game_map[p.last_game_key_name].mission_title
                row['last_mission_name'] = title
            else:
                row['last_mission_name'] = None
            row['player_rating'] = p.rating
            rows.append(row)

        # Figure out the next show url, if any (Show top N)
        show_count = count + SHOW_COUNT_INCREMENT
        if show_count > SHOW_COUNT_MAX:
            show_count = SHOW_COUNT_MAX
        show_url = ''
        if len(rows) == count and show_count > count:
            show_url = '%s?count=%d' % (config.LEADERBOARD_URL, show_count)
            if player_name != '':
                show_url = '%s&p=%s' % (show_url, player_name)

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': config.TAB_LEADERBOARD,
            'rows': rows,
            'chevron_image_url': config.CHEVRON_IMAGE_URL,
            'show_count' : show_count,
            'show_url' : show_url,
        }
        
        self.set_caching_headers(config.INFOPAGE_MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'leaderboard.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #15
0
ファイル: games.py プロジェクト: vikas100/hostile-takeover
    def get(self):
        # Get player name, if any
        player_name = self.request.get('p')

        # Get user name, if any. If none, use player name
        user_name = self.request.get('u')
        if not user_name:
            user_name = player_name

        # All or not
        all = False
        if self.request.get('a') == '1':
            all = True
        if not player_name and not user_name:
            all = True

        # Get the row count and validate
        count_str = self.request.get('count')
        if count_str == '':
            count = SHOW_COUNT_INCREMENT
        else:
            count = int(count_str)
            if count < 0:
                count = 0
            if count > SHOW_COUNT_MAX:
                count = SHOW_COUNT_MAX 

        # Retrieve gamestats
        rows = self.get_gamestats_rows(player_name, user_name, count, all)

        # Figure out the next show url, if any (Show top N)
        show_count = count + SHOW_COUNT_INCREMENT
        if show_count > SHOW_COUNT_MAX:
            show_count = SHOW_COUNT_MAX
        show_url = ''
        if len(rows) == count and show_count > count:
            show_url = self.get_games_url(player_name, user_name, all,
                    show_count)

        # If player_name and user_name are the same, the Games tab is selected
        selected_tab = config.TAB_NONE
        if player_name == user_name:
            selected_tab = config.TAB_GAMES

        # Render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(player_name),
            'selected_tab': selected_tab,
            'rows': rows,
            'chevron_image_url': config.CHEVRON_IMAGE_URL,
            'winner_small_image_url': config.WINNER_SMALL_IMAGE_URL,
            'show_url': show_url,
            'show_count': show_count,
            'all': all,
            'user_name': user_name,
            'selector_url': self.get_games_url(player_name, user_name, not all)
        }

        self.set_caching_headers(config.INFOPAGE_MAX_AGE_SECONDS)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'games.xhtml')
        self.response.out.write(template.render(path, template_values))
コード例 #16
0
    def get(self):
        # Requires an authenticated user with proper access rights
        account = accounts.account()
        if not account or not account.SEE_PLAYER_INFO_ACCESS_RIGHT:
            self.redirect(users.create_logout_url(self.request.uri))

        # Get args
        self.get_args()

        # Query for results
        keys = []
        if self.user_name:
            keys.append('player: %s' % self.user_name)
        if self.did:
            keys.append('did: %s' % self.did)
        if self.ip_address:
            keys.append('ip: %s' % self.ip_address)
        if len(keys) != 0:
            query_string = '%s' % ', '.join(keys)
        else:
            query_string = 'all'

        # If json request, perform that response
        if self.request.get('j'):
            self.response.headers['Content-Type'] = 'text/plain'
            data = dict(query_string=query_string,
                        tables=self.collect_tables())
            self.response.out.write(json.dumps(data))
            return

        # Calc all-url
        if self.player_name:
            all_url = '%s?p=%s&c=%d' % (config.PLAYERDETAIL_URL,
                                        self.player_name, self.count)
        else:
            all_url = '%s?c=%d' % (config.PLAYERDETAIL_URL, self.count)

        # Calc count-url
        if self.player_name:
            if self.q:
                count_url = '%s?p=%s&q=%s' % (config.PLAYERDETAIL_URL,
                                              self.player_name, self.q)
            else:
                count_url = '%s?p=%s' % (config.PLAYERDETAIL_URL,
                                         self.player_name)
        else:
            if self.q:
                count_url = '%s?q=%s' % (config.PLAYERDETAIL_URL, self.q)
            else:
                count_url = '%s?x=1' % config.PLAYERDETAIL_URL

        # Otherwise render the template and serve the response
        template_values = {
            'tabs': config.get_tabs(self.player_name, account),
            'selected_tab': config.TAB_NONE,
            'query_string': query_string,
            'show_all': query_string != 'all',
            'all_url': all_url,
            'count_url': count_url,
            'tables': self.collect_tables(),
            'player_name': self.player_name,
            'count': self.count,
            'show_counts': [50, 100, 250, 500, 1000],
        }

        self.set_caching_headers(60)
        self.response.headers['Content-Type'] = 'application/xhtml+xml'
        path = os.path.join(os.path.dirname(__file__), 'playerdetail.xhtml')
        self.response.out.write(template.render(path, template_values))