bug fixing cardstories

cardstories was tested manually and the blockers were fixed. The resulting release was installed and includes the solo mode.

duplicate players

If a player tries the solo mode and is presented with a game in which (s)he already participated, a duplicate record error occurs. Since the solution is probably to create players dedicated to the solo mode in order for the games to not be associated with existing players, a workaround was preferred to a more sophisticated solution. Implementing dedicated players is too early as the solo mode has not yet been tested. The selected game for solo mode is checked and redrawn if the requesting player already participated in it:

        while True:
            count -= 1
            transaction.execute("SELECT id, owner_id, board FROM games WHERE state = 'complete' ORDER BY RANDOM() LIMIT 1")
            ( game_from, owner_id, board ) = transaction.fetchall()[0]
            transaction.execute("SELECT count(*) FROM player2game WHERE game_id = ? AND player_id = ?", [ game_from, player_to ])
            if transaction.fetchone()[0] == 0:
                break
            elif count <= 0:
                return False

plugin interception

A plugin may delete the action argument from a request in order to transparently bypass the handling of the request. It is used by solo mode to implement the action=solo command and prevent the regular handler from doing anything. The handler did not return the result of the callback but the arguments of the incoming request. When asking for a solo game the user was sent back to the lobby instead of being presented with the first step of the game.
An additional argument containing the result of the previous callbacks is given to the handle function to enable it to transparently return it.

duplicate poll

The poll function in the client is used to get notifications when something changes in the server. When a game is created, the return of the poll must be ignored to avoid duplicate notifications and disturbing refresh from the user point of view. It was forgoten in the solo funciton and added to it:

        solo: function(player_id, root) {
            this.poll_discard(root);
            var $this = this;
...