Showing preview only (1,002K chars total). Download the full file or copy to clipboard to get everything.
Repository: happypepper/DeepHoldem
Branch: master
Commit: 68953137dd9d
Files: 121
Total size: 63.7 MB
Directory structure:
gitextract_p10ow7qd/
├── .gitignore
├── ACPCServer/
│ ├── LICENCE
│ ├── Makefile
│ ├── README
│ ├── README.submission
│ ├── acpc_play_match.pl
│ ├── all_in_expectation.c
│ ├── bm_run_matches.c
│ ├── bm_server.c
│ ├── bm_server.config
│ ├── bm_widget.c
│ ├── dealer.c
│ ├── evalHandTables
│ ├── example_player.c
│ ├── example_player.kuhn.limit.3p.sh
│ ├── example_player.limit.2p.sh
│ ├── example_player.limit.3p.sh
│ ├── example_player.nolimit.2p.sh
│ ├── example_player.nolimit.3p.sh
│ ├── game.c
│ ├── game.h
│ ├── holdem.limit.2p.reverse_blinds.game
│ ├── holdem.limit.3p.game
│ ├── holdem.nolimit.2p.reverse_blinds.game
│ ├── holdem.nolimit.3p.game
│ ├── kuhn.limit.3p.game
│ ├── leduc.game
│ ├── net.c
│ ├── net.h
│ ├── play_match.pl
│ ├── protocol.odt
│ ├── rng.c
│ ├── rng.h
│ ├── sum_values.pl
│ └── validate_submission.pl
├── Data/
│ ├── .gitignore
│ └── Models/
│ └── NoLimit/
│ ├── flop/
│ │ └── final_cpu.info
│ ├── preflop-aux/
│ │ ├── final_cpu.info
│ │ └── final_cpu.model
│ ├── river/
│ │ └── final_cpu.info
│ └── turn/
│ └── final_cpu.info
├── Source/
│ ├── ACPC/
│ │ ├── Tests/
│ │ │ └── test_parser.lua
│ │ ├── acpc_game.lua
│ │ ├── network_communication.lua
│ │ └── protocol_to_node.lua
│ ├── DataGeneration/
│ │ ├── aux_data_generation.lua
│ │ ├── data_generation.lua
│ │ ├── main_aux_data_generation.lua
│ │ ├── main_data_generation.lua
│ │ ├── random_card_generator.lua
│ │ └── range_generator.lua
│ ├── Game/
│ │ ├── Evaluation/
│ │ │ └── evaluator.lua
│ │ ├── bet_sizing.lua
│ │ ├── card_to_string_conversion.lua
│ │ └── card_tools.lua
│ ├── Lookahead/
│ │ ├── Tests/
│ │ │ ├── ranges/
│ │ │ │ ├── flop-situation1-p1.txt
│ │ │ │ ├── flop-situation1-p2.txt
│ │ │ │ ├── flop-situation2-p1.txt
│ │ │ │ ├── flop-situation2-p2.txt
│ │ │ │ ├── flop-situation3-p1.txt
│ │ │ │ ├── flop-situation3-p2.txt
│ │ │ │ ├── flop-situation4-p1.txt
│ │ │ │ ├── flop-situation4-p2.txt
│ │ │ │ ├── situation-p1.txt
│ │ │ │ ├── situation-p2.txt
│ │ │ │ ├── situation2-p1.txt
│ │ │ │ ├── situation2-p2.txt
│ │ │ │ ├── situation3-p1.txt
│ │ │ │ └── situation3-p2.txt
│ │ │ ├── test_flop_nl.lua
│ │ │ ├── test_preflop_nl.lua
│ │ │ ├── test_river_nl.lua
│ │ │ └── test_turn_nl.lua
│ │ ├── cfrd_gadget.lua
│ │ ├── lookahead.lua
│ │ ├── lookahead_builder.lua
│ │ ├── mock_resolving.lua
│ │ └── resolving.lua
│ ├── Nn/
│ │ ├── Bucketing/
│ │ │ ├── .gitignore
│ │ │ ├── flop_tools.lua
│ │ │ ├── river_tools.lua
│ │ │ └── turn_tools.lua
│ │ ├── bucket_conversion.lua
│ │ ├── bucketer.lua
│ │ ├── cpu_gpu_model_converter.lua
│ │ ├── masked_huber_loss.lua
│ │ ├── mock_nn_terminal.lua
│ │ ├── net_builder.lua
│ │ ├── next_round_value.lua
│ │ ├── next_round_value_pre.lua
│ │ ├── next_round_value_test.lua
│ │ └── value_nn.lua
│ ├── Player/
│ │ ├── continual_resolving.lua
│ │ ├── deepstack.lua
│ │ ├── deepstack_server.lua
│ │ ├── manual_player.lua
│ │ ├── slum_util.py
│ │ └── slumbot_player.py
│ ├── Settings/
│ │ ├── arguments.lua
│ │ ├── constants.lua
│ │ └── game_settings.lua
│ ├── TerminalEquity/
│ │ └── terminal_equity.lua
│ ├── Training/
│ │ ├── data_stream.lua
│ │ ├── main_train.lua
│ │ ├── raw_converter.lua
│ │ └── train.lua
│ ├── Tree/
│ │ ├── Tests/
│ │ │ ├── test_tree_builder.lua
│ │ │ ├── test_tree_cfr.lua
│ │ │ ├── test_tree_strategy_fillings.lua
│ │ │ ├── test_tree_values.lua
│ │ │ └── test_tree_visualiser.lua
│ │ ├── strategy_filling.lua
│ │ ├── tree_builder.lua
│ │ ├── tree_cfr.lua
│ │ ├── tree_strategy_filling.lua
│ │ ├── tree_values.lua
│ │ └── tree_visualiser.lua
│ └── tools.lua
├── readme.md
└── torch/
├── extra/
│ └── cutorch/
│ └── TensorMath.lua
└── pkg/
└── torch/
└── TensorMath.lua
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
**/a.out
**/.DS_Store
================================================
FILE: ACPCServer/LICENCE
================================================
Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Except as contained in this notice, the name(s) of the above copyright holders
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: ACPCServer/Makefile
================================================
CC = gcc
CFLAGS = -O3 -Wall
PROGRAMS = all_in_expectation bm_run_matches dealer example_player
all: $(PROGRAMS)
clean:
rm -f $(PROGRAMS)
all_in_expectation: all_in_expectation.c game.c game.h rng.c rng.h net.c net.h
$(CC) $(CFLAGS) -o $@ all_in_expectation.c game.c rng.c net.c
bm_server: bm_server.c game.c game.h rng.c rng.h net.c net.h
$(CC) $(CFLAGS) -o $@ bm_server.c game.c rng.c net.c
bm_widget: bm_widget.c net.c net.h
$(CC) $(CFLAGS) -o $@ bm_widget.c net.c
bm_run_matches: bm_run_matches.c net.c net.h
$(CC) $(CFLAGS) -o $@ bm_run_matches.c net.c
dealer: game.c game.h evalHandTables rng.c rng.h dealer.c net.c net.h
$(CC) $(CFLAGS) -o $@ game.c rng.c dealer.c net.c
example_player: game.c game.h evalHandTables rng.c rng.h example_player.c net.c net.h
$(CC) $(CFLAGS) -o $@ game.c rng.c example_player.c net.c
================================================
FILE: ACPCServer/README
================================================
This README contains information about the server code for the Annual Computer
Poker Competition. Please see the LICENCE file for information regarding the
code's licence.
===== Software Requirements =====
This code was developed and tested for use on Unix based systems. Though it
may work on other platforms, there are no guarantees.
You will need standard Unix developer tools to build the software including
gcc, and make.
===== Getting Started =====
* Building the code
The Makefile provides instructions for compiling the code. Running 'make' from
the command line will compile the required programs.
* The programs
dealer - Communicates with agents connected over sockets to play a game
example_player - A sample player implemented in C
play_match.pl - A perl script for running matches with the dealer
Usage information for each of the programs is available by running the
executable without any arguments.
* Playing a match
The fastest way to start a match is through the play_match.pl script. An
example follows:
$ ./play_match.pl matchName holdem.limit.2p.reverse_blinds.game 1000 0 Alice ./example_player.limit.2p.sh Bob ./example_player.limit.2p.sh
After play_match.pl finishes running, there will be two output files for the
dealer and two output files for each player in the game:
matchName.err - The stderr from dealer including the messages sent to players
matchName.log - The log for the hands played during the match
matchName.playerN.std - stdout from player N
matchName.playerN.err - stderr from player N
Note, play_match.pl expects player executables that take exactly two arguments:
the server IP followed by the port number. The executable must be specified
such that it is either a path or the executable name if it can be found in your
$PATH.
If you need to pass specific arguments to you agent, we suggest wrapping it in
another script. play_match.pl will pass any extra arguments to dealer.
Matches can also be started by calling dealer and starting the players
manually. More information on this is contained in the dealer section below.
* dealer
Running dealer will start a process that waits for other players to connect to
it. After starting dealer, it will output something similar to the following:
$ ./dealer matchName holdem.limit.2p.reverse_blinds.game 1000 0 Alice Bob
16177 48777
# name/game/hands/seed matchName holdem.limit.2p.reverse_blinds.game 1000 0
#--t_response 10000
#--t_hand 600000
#--t_per_hand 6000
On the first line of output there should be as many numbers as there are
players in the game (in this case, "16177" and "48777"). These are the ports
the dealer is listening on for players. Note that these ports are specific to
the positions for players in the game.
Once all the players have connected to the game, the dealer will begin playing
the game and outputting the messages sent to each player. After the end of the
match, you should have a log file called matchName.log in the directory where
dealer was started with the hands that were played.
Matches can also be started by starting the dealer and connecting the
executables by hand. This can be useful if you want to start your own program
in a way that is difficult to script (such as running it in a debugger).
==== Game Definitions ====
The dealer takes game definition files to determine which game of poker it
plays. Please see the included game definitions for some examples. The code
for handling game definitions is found in game.c and game.h.
Game definitions can have the following fields (case is ignored):
gamedef - the starting tag for a game definition
end gamedef - ending tag for a game definition
stack - the stack size for each player at the start of each hand (for no-limit)
blind - the size of the blinds for each player (relative to the dealer)
raisesize - the size of raises on each round (for limit games)
limit - specifies a limit game
nolimit - specifies a no-limit game
numplayers - number of players in the game
numrounds - number of betting rounds per hand of the game
firstplayer - the player that acts first (relative to the dealer) on each round
maxraises - the maximum number of raises on each round
numsuits - the number of different suits in the deck
numranks - the number of different ranks in the deck
numholecards - the number of private cards to deal to each player
numboardcards - the number of cards revealed on each round
Empty lines or lines with '#' as the very first character will be ignored
If you are creating your own game definitions, please note that game.h defines
some constants for maximums in games (e.g., number of rounds). These may need
to be changed for games outside of the what is being run for the Annual
Computer Poker Competition.
================================================
FILE: ACPCServer/README.submission
================================================
#############################################################
# Please fill out the following information about your team
#############################################################
Team Name:
Agent Name (can be the same as team name):
For each team member, please list the following:
Name, Team leader (y/n)?, e-mail, Academic (y/n, position - e.g., PhD student)?, University/Business affiliation, Location (city, province/state, country)
Was this submission part of an academic class project? What level of class
(undergraduate/graduate)?
###########################################################################
# Please provide as much information about your agent as possible as the
# competition organizers are very interested in knowing more about the
# techniques used by our competitors.
###########################################################################
1) Is your agent dynamic? That is, does its strategy change throughout the
course of a match, or is the strategy played the same throughout the match?
2) Does your agent use a (approximate) Nash equilibrium strategy?
3) Does your agent attempt to model your opponents? If so, does it do so
online during the competition or offline from data (e.g., using logs of play or
the benchmark server)?
4) Does your agent use techniques that would benefit from additional CPU time
during the competition?
5) Does your agent use techniques that would benefit from additional RAM during
the competition?
6) Would you agent benefit from additional disk space?
One/Two Paragraph Summary of Technique
References to relevant papers, if any
================================================
FILE: ACPCServer/acpc_play_match.pl
================================================
#!/usr/bin/perl
# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
use Socket;
use File::Basename;
$hostname = `hostname` or die "could not get hostname";
chomp $hostname;
@hostent = gethostbyname( $hostname );
$#hostent >= 4 or die "could not look up $hostname";
$hostip = inet_ntoa( $hostent[ 4 ] );
$#ARGV >= 3 or die "usage: play_match.pl matchName gameDefFile #Hands rngSeed player1name player1exe player2name player2exe ... [options]";
$numPlayers = -1;
open FILE, '<', $ARGV[ 1 ] or die "couldn't open game definition $ARGV[ 1 ]";
while( $_ = <FILE> ) {
@_ = split;
if( uc( $_[ 0 ] ) eq 'NUMPLAYERS' ) {
$numPlayers = $_[ $#_ ];
}
}
close FILE;
$numPlayers > 1 or die "couldn't get number of players from $ARGV[ 1 ]";
$#ARGV >= 3 + $numPlayers * 2 or die "too few players on command line";
pipe STDINREADPIPE, STDINWRITEPIPE or die "couldn't create stdin pipe";
pipe STDOUTREADPIPE, STDOUTWRITEPIPE or die "couldn't create stdout pipe";
$dealerPID = fork();
if( $dealerPID == 0 ) {
# we're the child
# replace standard in and standard out with pipe
close STDINWRITEPIPE;
close STDOUTREADPIPE;
open STDIN, '<&STDINREADPIPE' or die "can't dup STDIN";
open STDOUT, '>&STDOUTWRITEPIPE' or die "can't dup STDOUT";
open STDERR, ">>$ARGV[ 0 ].err" or die "can't open log file $ARGV[ 0 ].err";
@args = ( "dealer", $ARGV[ 0 ], $ARGV[ 1 ],
$ARGV[ 2 ], $ARGV[ 3 ] );
# add names to the arguments
for( $p = 0; $p < $numPlayers; ++$p ) {
push @args, $ARGV[ 4 + $p * 2 ];
}
# add any extra arguments (options?) to the arguments
for( $i = 4 + $numPlayers * 2; $i <= $#ARGV; ++$i ) {
push @args, $ARGV[ $i ];
}
exec { "./dealer" } @args or die "Couldn't run dealer";
}
close STDINREADPIPE;
close STDOUTWRITEPIPE;
$_ = <STDOUTREADPIPE> or die "couldn't read port description from dealer";
@_ = split;
$#_ + 1 >= $numPlayers or die "couldn't get enough ports from $_";
for( $p = 0; $p < $numPlayers; ++$p ) {
$playerPID[ $p ] = fork();
if( $playerPID[ $p ] == 0 ) {
# we're the child
# log standard out and standard error
open STDOUT, ">$ARGV[ 0 ].player$p.std"
or die "can't dup player $p STDOUT";
open STDERR, ">$ARGV[ 0 ].player$p.err"
or die "can't dup player $p STDERR";
($playerExec, $playerDir) = fileparse( $ARGV[ 4 + $p * 2 + 1 ] );
chdir $playerDir or die "Can't cd to $playerDir: $!\n";
exec { "./$playerExec" } ( "./$playerExec", $hostip, $_[ $p ] )
or die "couldn't run $playerExec from $playerDir for player $p";
}
}
$_ = <STDOUTREADPIPE>;
for( $p = 0; $p < $numPlayers; ++$p ) {
waitpid( $playerPID[ $p ], 0 );
}
waitpid( $dealerPID, 0 );
$_ or die "couldn't get values from dealer";
print $_;
exit( 0 );
================================================
FILE: ACPCServer/all_in_expectation.c
================================================
/*
Copyright (C) 2014 by the Computer Poker Research Group, University of Alberta
*/
#include <stdlib.h>
#include <stdio.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <getopt.h>
#include "game.h"
#include "net.h"
void getUsedCards( const Game *game,
const State *state,
const int lastRound,
uint8_t *used )
{
int i, p;
/* start with no cards used */
memset( used, 0, sizeof( used[ 0 ] ) * game->numSuits * game->numRanks );
/* collect the player cards */
for( p = 0; p < game->numPlayers; ++p ) {
for( i = 0; i < game->numHoleCards; ++i ) {
used[ state->holeCards[ p ][ i ] ] = 1;
}
}
/* collect the board cards up to lastRound */
p = sumBoardCards( game, lastRound );
for( i = 0; i < p; ++i ) {
used[ state->boardCards[ i ] ] = 1;
}
}
int main( int argc, char **argv )
{
int stateEnd, r, i, p, deckSize, numBoards;
FILE *file;
Game *game;
State state;
uint8_t deck[ MAX_SUITS * MAX_RANKS ];
uint8_t used[ MAX_SUITS * MAX_RANKS ];
double value[ MAX_PLAYERS ];
char line[ 4096 ];
if( argc < 3 ) {
fprintf( stderr, "USAGE: %s game_def log_file\n", argv[ 0 ] );
exit( EXIT_FAILURE );
}
/* get the game definition */
file = fopen( argv[ 1 ], "r" );
if( file == NULL ) {
fprintf( stderr, "ERROR: could not open game definition %s\n", argv[ 1 ] );
exit( EXIT_FAILURE );
}
game = readGame( file );
if( game == NULL ) {
fprintf( stderr, "ERROR: could not read game %s\n", argv[ 1 ] );
exit( EXIT_FAILURE );
}
fclose( file );
/* get the log file */
file = fopen( argv[ 2 ], "r" );
if( file == NULL ) {
fprintf( stderr, "ERROR: could not open log file %s\n", argv[ 2 ] );
exit( EXIT_FAILURE );
}
/* read every line and process all hands */
while( fgets( line, 4096, file ) ) {
stateEnd = readState( line, game, &state );
if( stateEnd < 0 ) {
/* couldn't read a state from the line */
continue;
}
if( numAllIn( game, &state ) == 0
|| numFolded( game, &state ) + 1 >= game->numPlayers ) {
/* no one all in, or game didn't end in a showdown */
printf( "%s", line );
continue;
}
/* find last round where someone made an action */
for( r = state.round; r > 0; --r ) {
if( state.numActions[ r ] ) {
break;
}
}
if( r + 1 == game->numRounds ) {
/* there are no board cards left to roll out on the final round */
printf( "%s", line );
continue;
}
/* initialise values to 0 */
memset( value, 0, sizeof( value ) );
/* set up a deck containing all cards up to round r */
getUsedCards( game, &state, r, used );
deckSize = 0;
for( i = 0; i < game->numSuits * game->numRanks; ++i ) {
if( !used[ i ] ) {
deck[ deckSize ] = i;
++deckSize;
}
}
/* switch to using used[] as the index into deck[]
for the remaining cards used on the board
sort hands in ascending order, start with highest indexed hand */
const int bcStart = sumBoardCards( game, r );
const int numCards = sumBoardCards( game, game->numRounds - 1 ) - bcStart;
for( i = 0; i < numCards; ++i ) {
used[ i ] = deckSize - numCards + i;
state.boardCards[ bcStart + i ] = deck[ used[ i ] ];
}
/* try every possible board */
numBoards = 0;
while( 1 ) {
/* get the values */
for( p = 0; p < game->numPlayers; ++p ) {
value[ p ] += valueOfState( game, &state, p );
}
/* move on to the next board */
++numBoards;
/* find position of first card we can decrement */
i = 0;
while( used[ i ] == i && i < numCards ) {
++ i;
}
if( i == numCards ) {
/* can't decrement any cards, so we're done */
break;
}
/* decrement the card */
--used[ i ];
state.boardCards[ bcStart + i ] = deck[ used[ i ] ];
/* fill in all earlier cards with highest possible index */
while( i > 0 ) {
/* move to previous card, set index to one lower then current card */
--i;
used[ i ] = used[ i + 1 ] - 1;
state.boardCards[ bcStart + i ] = deck[ used[ i ] ];
}
}
/* do the printout - start with the state */
if( line[ stateEnd ] != 0 ) {
if( line[ stateEnd ] != ':' && line[ stateEnd ] != '\n' ) {
fprintf( stderr, "ERROR: expected input of STATE:VALUES:PLAYERS\n" );
exit( EXIT_FAILURE );
}
line[ stateEnd ] = 0;
++stateEnd;
}
printf( "%s:", line );
/* print out the averaged values */
for( p = 0; p < game->numPlayers; ++p ) {
printf( p ? "|%lf" : "%lf", value[ p ] / (double)numBoards );
}
/* find the player names in the state line */
for( i = stateEnd; line[ i ] && line[ i ] != ':'; ++i );
if( line[ i ] == ':' ) {
printf( "%s", &line[ i ] );
} else {
printf( "\n" );
}
}
fclose( file );
exit( EXIT_SUCCESS );
}
================================================
FILE: ACPCServer/bm_run_matches.c
================================================
#include <stdlib.h>
#include <stdio.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/wait.h>
#include <errno.h>
#include "net.h"
#define ARG_SERVERNAME 1
#define ARG_SERVERPORT 2
#define ARG_BOT_COMMAND 7
#define ARG_MIN_ARGS 6
static void printUsage( FILE *file )
{
fprintf( file, "Sample usages:\n" );
fprintf( file, " bm_run_matches <bm_hostname> <bm_port> <username> <pw> "
"games\n" );
fprintf( file, " See a list of possible opponents\n" );
fprintf( file, " bm_run_matches <bm_hostname> <bm_port> <username> <pw> "
"run 2pl <local script> <# runs> <tag> <seed> <player1> "
"<player2>\n" );
fprintf( file, " Run two-player limit matches\n" );
fprintf( file, " bm_run_matches <bm_hostname> <bm_port> <username> <pw> "
"run 2pn <local script> <# runs> <tag> <seed> <player1> "
"<player2>\n" );
fprintf( file, " Run two-player no-limit matches\n" );
fprintf( file, " bm_run_matches <bm_hostname> <bm_port> <username> <pw> "
"run 3pl <local script> <# runs> <tag> <seed> <player1> <player2> "
"<player3>\n" );
fprintf( file, " Run three-player limit matches\n" );
fprintf( file, " bm_run_matches <bm_hostname> <bm_port> <username> <pw> "
"rerun 2pl <local script> <match index> <tag> <seed> <player1> "
"<player2> (<player3>)\n" );
fprintf( file, " Rerun a match that failed\n" );
fprintf( file, "\n" );
fprintf( file, "<username> is your benchmark server username assigned to "
"you by the competition chair\n" );
fprintf( file, "<pw> is your benchmark server password assigned to you by "
"the competition chair\n" );
fprintf( file, "<local script> is the script that runs your agent locally. "
"It must take a hostname/IP and a port\n" );
fprintf( file, "<num runs> is the number of matches you want to run\n" );
fprintf( file, "<tag> is a name for this set of matches which will appear "
"in the names of the log files\n" );
fprintf( file, "<seed> is a seed used to generate the random seeds that "
"determine the cards in each match\n" );
fprintf( file, "<player-n> is either the name of an opponent or \"local\" "
"for your local agent\n" );
fprintf( file, "\n" );
fprintf( file, "To run N duplicate heads-up matches, do one run of N "
"matches with a given seed, then run a second set of N matches "
"with the same seed but the order of the players reversed\n" );
fprintf( file, "\n" );
fprintf( file, "If one match in a set fails, you can use the \"rerun\" "
"command to rerun the specified match with the specified seed. "
"For example, if you tried to run twenty matches with seed 0 and "
"the last match failed, you could use the \"rerun\" command with "
"seed 0 and match index 19.\n" );
}
int main( int argc, char **argv )
{
int sock, i;
pid_t childPID;
uint16_t port;
ReadBuf *fromServer;
fd_set readfds;
char line[ READBUF_LEN ];
if( argc < ARG_MIN_ARGS ) {
printUsage( stderr );
exit( EXIT_FAILURE );
}
/* connect to the server */
if( sscanf( argv[ ARG_SERVERPORT ], "%"SCNu16, &port ) < 1 ) {
fprintf( stderr, "ERROR: invalid port %s\n", argv[ ARG_SERVERPORT ] );
exit( EXIT_FAILURE );
}
sock = connectTo( argv[ ARG_SERVERNAME ], port );
if( sock < 0 ) {
exit( EXIT_FAILURE );
}
// EJ additions 9/3/2012
// Turn on keep-alive for socket connection with more frequent checking
// than the Linux default. What I've observed is that if a socket
// connection is idle for long enough it gets dropped. This only
// happens for some users.
int on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
#ifdef __linux__
// Not sure what this should be
int num_before_failure = 2;
if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &num_before_failure,
sizeof(num_before_failure)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
// First check after 60 seconds
int initial_secs = 60;
if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &initial_secs,
sizeof(initial_secs)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
// Thereafter, also check every 60 seconds
int interval_secs = 60;
if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &interval_secs,
sizeof(interval_secs)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
#endif
/* set up read buffers */
fromServer = createReadBuf( sock );
/* write to server */
line[0] = 0;
for( i = 3; i < argc; ++i ) {
strcat( line, argv[i] );
if ( i < argc - 1 ) {
strcat( line, " " );
}
}
strcat( line, "\n" );
int len = strlen(line);
if( write( sock, line, len ) < 0 ) {
fprintf( stderr, "ERROR: failed while sending to server\n" );
exit( EXIT_FAILURE );
}
/* main loop */
while( 1 ) {
/* clean up any children */
while( waitpid( -1, NULL, WNOHANG ) > 0 );
/* wait for input */
FD_ZERO( &readfds );
FD_SET( sock, &readfds );
i = select( sock + 1, &readfds, NULL, NULL, NULL );
if( i < 0 ) {
fprintf( stderr, "ERROR: select failed\n" );
exit( EXIT_FAILURE );
}
if( i == 0 ) {
/* nothing ready - shouldn't happen without timeout */
continue;
}
/* handle server messages */
if( FD_ISSET( sock, &readfds ) ) {
/* get the input */
while( ( i = getLine( fromServer, READBUF_LEN, line, 0 ) ) >= 0 ) {
if( i == 0 ) {
/* This could be an error or could just signify successful
completion of all matches */
fprintf( stderr, "Server closed connection\n" );
exit( EXIT_SUCCESS );
}
/* check for server commands */
if( strncasecmp( line, "run ", 4 ) == 0 ) {
/* split the rest of the line into name ' ' port */
for( i = 4; line[ i ]; ++i ) {
if( line[ i ] == ' ' ) {
/* found the separator */
line[ i ] = 0;
break;
}
}
printf( "starting match %s:%s", &line[ 4 ], &line[ i + 1 ] );
fflush( stdout );
/* run `command machine port` */
childPID = fork();
if( childPID < 0 ) {
fprintf( stderr, "ERROR: fork() failed\n" );
exit( EXIT_FAILURE );
}
if( childPID == 0 ) {
/* child runs the command */
execl( argv[ ARG_BOT_COMMAND ],
argv[ ARG_BOT_COMMAND ],
&line[ 4 ],
&line[ i + 1 ],
NULL );
fprintf( stderr,
"ERROR: could not run %s\n",
argv[ ARG_BOT_COMMAND ] );
exit( EXIT_FAILURE );
}
} else {
/* just a message, print it out */
if( fwrite( line, 1, i, stdout ) < 0 ) {
fprintf( stderr, "ERROR: failed while printing server message\n" );
exit( EXIT_FAILURE );
}
fflush( stdout );
if( ! strcmp( line, "Matches finished\n") ) {
exit( EXIT_SUCCESS );
}
}
}
}
}
return EXIT_SUCCESS;
}
================================================
FILE: ACPCServer/bm_server.c
================================================
/*
Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
*/
#include <stdlib.h>
#include <stdio.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <assert.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include "game.h"
#include "net.h"
#include "rng.h"
#define STATUS_CLOSED 0
#define STATUS_UNVALIDATED 1
#define STATUS_OKAY 2
#define BM_DEALER "dealer"
#define BM_LOGDIR "logs"
#define BM_DEALER_WAIT_SECS 5
#define BM_MAX_IOWAIT_SECS 1
typedef struct LLPoolEntry_struct {
struct LLPoolEntry_struct *next;
struct LLPoolEntry_struct *prev;
char data[ 0 ];
} LLPoolEntry;
typedef struct {
LLPoolEntry *head;
LLPoolEntry *free;
int dataSize;
int numEntries;
} LLPool;
/* structure giving the specification for a local bot */
typedef struct {
char *name;
char *command;
} BotSpec;
/* structure giving the specification for a user */
typedef struct {
char *name;
char *passwd;
struct timeval waitStart;
} UserSpec;
typedef struct {
uint16_t maxMatchRuns; /* maximum number of runs for a match */
uint16_t maxRunningJobs; /* maximum simultaneous jobs at a time for game
0 disables the check */
uint32_t matchHands; /* number of hands in a match */
Game *game;
char *gameFile;
LLPool *bots;
int curRunningJobs;
} GameConfig;
typedef struct {
uint16_t port;
uint16_t maxRunningBots; /* maximum simultaneous bots at a time
0 disables the check */
uint16_t startupTimeoutSecs; /* maximum time to wait for clients to connect
0 disables the timer */
uint16_t responseTimeoutSecs; /* maximum time to wait for clients to respond
with an action */
uint16_t handTimeoutSecs; /* maximum time to allowed per hand of play */
uint16_t avgHandTimeSecs; /* average time per hand allowed for the match */
LLPool *games;
LLPool *users;
} Config;
typedef struct {
int status;
UserSpec *user; /* NULL when status is STATUS_UNVALIDATED */
ReadBuf *connBuf;
} Connection;
typedef struct {
GameConfig *gameConf;
UserSpec *user;
int numRuns;
rng_state_t rng;
uint32_t rngSeed;
int useRngForSeed; /* 0: use rngSeed as seed for each dealer run
1: use genrand_int32( match->rng ) */
char *tag;
struct timeval queueTime;
struct {
int isNetworkPlayer;
LLPoolEntry *entry; /* connection if network player, bot otherwise */
} players[ MAX_PLAYERS ];
int isRunning;
} Match;
typedef struct {
pid_t dealerPID;
pid_t botPID[ MAX_PLAYERS ];
LLPoolEntry *matchEntry;
char *tag; /* based on tag from the match for this job */
uint16_t ports[ MAX_PLAYERS ];
} MatchJob;
typedef struct {
int listenSocket;
LLPool *conns;
LLPool *matches;
LLPool *jobs;
rng_state_t rng;
char *hostname;
int devnullfd;
} ServerState;
LLPool *newLLPool( const int dataSize )
{
LLPool *pool;
pool = (LLPool*)malloc( sizeof( LLPool ) );
assert( pool != 0 );
pool->head = NULL;
pool->free = NULL;
pool->dataSize = dataSize;
pool->numEntries = 0;
return pool;
}
int entryInList( LLPoolEntry *list, LLPoolEntry *entry )
{
while( list ) {
if( entry == list ) {
return 1;
}
if( list->next ) {
assert( list->next->prev == list );
}
list = list->next;
}
return 0;
}
/* add an object to the pool. data must have a size of pool->dataSize */
LLPoolEntry *LLPoolAddItem( LLPool *pool, void *item )
{
LLPoolEntry *entry;
if( pool->free ) {
entry = pool->free;
pool->free = entry->next;
} else {
entry = (LLPoolEntry*)malloc( sizeof( LLPoolEntry ) + pool->dataSize );
assert( entry != 0 );
}
assert( !entryInList( pool->head, entry ) );
entry->next = pool->head;
entry->prev = NULL;
memcpy( entry->data, item, pool->dataSize );
if( pool->head ) {
pool->head->prev = entry;
}
pool->head = entry;
++pool->numEntries;
return entry;
}
/* remove an item from the pool, placing it in the free list.
entry must have been generated by LLPoolAddItem( pool, ... )
(that is, calling LLPoolRemoveEntry on an entry from another pool
is potentially a very bad idea...) */
void LLPoolRemoveEntry( LLPool *pool, LLPoolEntry *entry )
{
if( entry->prev ) {
assert( entry->prev->next == entry );
entry->prev->next = entry->next;
} else {
assert( pool->head == entry );
pool->head = entry->next;
}
if( entry->next ) {
assert( entry->next->prev == entry );
entry->next->prev = entry->prev;
}
assert( !entryInList( pool->free, entry ) );
if( pool->free ) {
pool->free->prev = entry;
}
entry->next = pool->free;
pool->free = entry;
--pool->numEntries;
}
/* LLPool iterator start */
LLPoolEntry *LLPoolFirstEntry( LLPool *pool )
{
return pool->head;
}
/* removing entries while iterating through the list is fine, as
long as cur is not the entry being removed. */
LLPoolEntry *LLPoolNextEntry( LLPoolEntry *cur )
{
if( cur ) {
return cur->next;
}
return NULL;
}
void *LLPoolGetItem( LLPoolEntry *entry )
{
return &entry->data;
}
void printUsage( FILE *file )
{
fprintf( file, "usage: bm_server config_file\n" );
}
void setGameDefaults( GameConfig *gameConf )
{
gameConf->maxMatchRuns = 10;
gameConf->maxRunningJobs = 1;
gameConf->matchHands = 5000;
gameConf->game = NULL;
gameConf->gameFile = NULL;
gameConf->bots = newLLPool( sizeof( BotSpec ) );
gameConf->curRunningJobs = 0;
}
void setDefaults( Config *conf )
{
conf->port = 54000;
conf->maxRunningBots = 0;
conf->startupTimeoutSecs = 600;
conf->responseTimeoutSecs = 6000; /* Value from 2011 ACPC */
conf->handTimeoutSecs = 3000 * 7; /* Not enforced for 2011 ACPC */
conf->avgHandTimeSecs = 70; /* Value from 2011 ACPC */
conf->games = newLLPool( sizeof( GameConfig ) );
conf->users = newLLPool( sizeof( UserSpec ) );
}
/* returns entry for bot on success, NULL on failure */
LLPoolEntry *findBot( const GameConfig *game, const char *name )
{
LLPoolEntry *cur;
for( cur = LLPoolFirstEntry( game->bots );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
if( !strcmp( ( (BotSpec *)LLPoolGetItem( cur ) )->name, name ) ) {
return cur;
}
}
return NULL;
}
void addBot( GameConfig *gameConf, const char *spec )
{
BotSpec bot;
char name[ READBUF_LEN ];
char command[ READBUF_LEN ];
/* split the line into name and command */
if( sscanf( spec, " %s %s", name, command ) < 2 ) {
fprintf( stderr, "BM_ERROR: could not get bot name and command from: %s",
spec );
exit( EXIT_FAILURE );
}
/* make sure there are no duplicates */
if( !strcmp( name, "LOCAL" ) ) {
fprintf( stderr, "BM_ERROR: LOCAL is a reserved bot name\n" );
exit( EXIT_FAILURE );
}
if( findBot( gameConf, name ) ) {
fprintf( stderr, "BM_ERROR: duplicate bot %s\n", name );
exit( EXIT_FAILURE );
}
/* add the bot */
bot.name = strdup( name );
bot.command = strdup( command );
LLPoolAddItem( gameConf->bots, &bot );
}
/* returns entry for user on success, NULL on failure */
LLPoolEntry *findUser( const Config *conf, const char *name )
{
LLPoolEntry *cur;
for( cur = LLPoolFirstEntry( conf->users );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
if( !strcmp( ( (UserSpec *)LLPoolGetItem( cur ) )->name, name ) ) {
return cur;
}
}
return NULL;
}
void addUser( Config *conf, const char *spec )
{
UserSpec user;
char name[ READBUF_LEN ];
char passwd[ READBUF_LEN ];
/* split the line into name and password */
if( sscanf( spec, " %s %s", name, passwd ) < 2 ) {
fprintf( stderr, "BM_ERROR: could not get user name and password from: %s",
spec );
exit( EXIT_FAILURE );
}
/* make sure there are no duplicates */
if( findUser( conf, name ) ) {
fprintf( stderr, "BM_ERROR: duplicate user %s\n", name );
exit( EXIT_FAILURE );
}
/* add the user */
user.name = strdup( name );
user.passwd = strdup( passwd );
gettimeofday( &user.waitStart, NULL );
LLPoolAddItem( conf->users, &user );
}
/* returns entry for game on success, NULL on failure */
LLPoolEntry *findGame( const Config *conf, const char *name )
{
LLPoolEntry *cur;
for( cur = LLPoolFirstEntry( conf->games );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
if( !strcmp( ( (GameConfig *)LLPoolGetItem( cur ) )->gameFile, name ) ) {
return cur;
}
}
return NULL;
}
/* validate a logon request
returns user on success, or NULL on failure */
UserSpec *validateLogon( const Config *conf, const char *line )
{
LLPoolEntry *cur;
char name[ READBUF_LEN ];
char passwd[ READBUF_LEN ];
if( sscanf( line, " %s %s", name, passwd ) < 2 ) {
return NULL;
}
for( cur = LLPoolFirstEntry( conf->users );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
UserSpec *user = (UserSpec *)LLPoolGetItem( cur );
if( !strcmp( user->name, name ) ) {
if( !strcmp( user->passwd, passwd ) ) {
return user;
}
return NULL;
}
}
return NULL;
}
void readConfig( const char *filename, Config *conf )
{
int start;
FILE *file;
GameConfig *gameConf;
char *line, lineBuf[ READBUF_LEN ];
file = fopen( filename, "r" );
if( file == NULL ) {
fprintf( stderr, "BM_ERROR: could not open configuration file %s\n",
filename );
exit( EXIT_FAILURE );
}
gameConf = NULL;
while( fgets( lineBuf, READBUF_LEN, file ) ) {
/* skip past white space at start of line */
start = 0; while( isspace( lineBuf[ start ] ) ) { ++start; }
line = &lineBuf[ start ];
/* ignore comments or empty lines */
if( line[ 0 ] == '#' || line[ 0 ] == ';'
|| line[ 0 ] == '\n' || line[ 0 ] == 0 ) {
continue;
}
if( strncasecmp( line, "port", 4 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: server port must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 4 ], "%"SCNu16, &conf->port ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get port from: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "game", 4 ) == 0 ) {
FILE *file;
GameConfig gc;
char game[ READBUF_LEN ];
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: can't define a game within another game block\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 4 ], " %s", game ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get game name from: %s", line );
exit( EXIT_FAILURE );
}
if( findGame( conf, game ) ) {
fprintf( stderr, "BM_ERROR: game %s has already been used\n", game );
exit( EXIT_FAILURE );
}
setGameDefaults( &gc );
gc.gameFile = strdup( game );
file = fopen( gc.gameFile, "r" );
if( file == NULL ) {
fprintf( stderr, "BM_ERROR: could not open game file %s\n", gc.gameFile );
exit( EXIT_FAILURE );
}
gc.game = readGame( file );
fclose( file );
if( gc.game == NULL ) {
fprintf( stderr, "BM_ERROR: could not read game %s", gc.gameFile );
exit( EXIT_FAILURE );
}
gameConf
= (GameConfig *)LLPoolGetItem( LLPoolAddItem( conf->games, &gc ) );
} else if( strncmp( line, "}", 1 ) == 0 ) {
/* finished game definition */
gameConf = NULL;
} else if( strncasecmp( line, "maxRunningBots", 14 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: maxRunningBots must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 14 ], "%"SCNu16, &conf->maxRunningBots ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum number of bots running from: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "startupTimeoutSecs", 18 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: startupTimeoutSecs must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 18 ], "%"SCNu16, &conf->startupTimeoutSecs ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum dealer startup timeout: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "responseTimeoutSecs", 19 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: responseTimeoutSecs must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 19 ], "%"SCNu16, &conf->responseTimeoutSecs ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum dealer action timeout: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "handTimeoutSecs", 15 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: handTimeoutSecs must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 15 ], "%"SCNu16, &conf->handTimeoutSecs ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum dealer hand timeout: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "avgHandTimeSecs", 15 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr, "BM_ERROR: avgHandTimeSecs must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 15 ], "%"SCNu16, &conf->avgHandTimeSecs ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get dealer average hand time: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "maxMatchRuns", 12 ) == 0 ) {
if( gameConf == NULL ) {
fprintf( stderr, "BM_ERROR: maxMatchRuns must be defined within a game block\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 12 ], "%"SCNu16, &gameConf->maxMatchRuns ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum number of runs in a match from: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "maxRunningJobs", 14 ) == 0 ) {
if( gameConf == NULL ) {
fprintf( stderr, "BM_ERROR: maxRunningJobs must be defined within a game block\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 14 ], "%"SCNu16, &gameConf->maxRunningJobs ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get maximum number of running jobs from: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "matchHands", 10 ) == 0 ) {
if( gameConf == NULL ) {
fprintf( stderr, "BM_ERROR: matchHands must be defined within a game block\n" );
exit( EXIT_FAILURE );
}
if( sscanf( &line[ 10 ], "%"SCNu32, &gameConf->matchHands ) < 1 ) {
fprintf( stderr, "BM_ERROR: could not get number of hands in a match from: %s", line );
exit( EXIT_FAILURE );
}
} else if( strncasecmp( line, "bot", 3 ) == 0 ) {
if( gameConf == NULL ) {
fprintf( stderr, "BM_ERROR: matchHands must be defined within a game block\n" );
exit( EXIT_FAILURE );
}
addBot( gameConf, &line[ 3 ] );
} else if( strncasecmp( line, "user", 4 ) == 0 ) {
if( gameConf != NULL ) {
fprintf( stderr,
"BM_ERROR: users must be defined outside of game blocks\n" );
exit( EXIT_FAILURE );
}
addUser( conf, &line[ 4 ] );
} else {
fprintf( stderr, "BM_ERROR: unknown configuration option %s", line );
exit( EXIT_FAILURE );
}
}
fclose( file );
}
void addConnection( ServerState *serv, const int sock )
{
Connection conn;
/* add the connection */
conn.status = STATUS_UNVALIDATED;
conn.user = NULL;
conn.connBuf = createReadBuf( sock );
if( conn.connBuf == 0 ) {
fprintf( stderr, "BM_ERROR: could not create read buffer for socket\n" );
exit( EXIT_FAILURE );
}
LLPoolAddItem( serv->conns, &conn );
}
int matchUsesConnection( const Match *match, const LLPoolEntry *connEntry )
{
int p;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( match->players[ p ].isNetworkPlayer
&& match->players[ p ].entry == connEntry ) {
return 1;
}
}
return 0;
}
void closeConnection( ServerState *serv, LLPoolEntry *connEntry )
{
Connection *conn = (Connection*)LLPoolGetItem( connEntry );
LLPoolEntry *cur, *next;
destroyReadBuf( conn->connBuf );
conn->status = STATUS_CLOSED;
/* remove any pending matches which relied on the connection */
for( cur = LLPoolFirstEntry( serv->matches ); cur != NULL; cur = next ) {
next = LLPoolNextEntry( cur );
Match *match = (Match *)LLPoolGetItem( cur );
if( matchUsesConnection( match, connEntry ) ) {
match->numRuns = 0;
}
}
}
void handleListenSocket( const Config *conf, ServerState *serv )
{
int sock;
struct sockaddr_in addr;
socklen_t addrLen;
addrLen = sizeof( addr );
sock = accept( serv->listenSocket, (struct sockaddr *)&addr, &addrLen );
if( sock < 0 ) {
fprintf( stderr, "WARNING: failed to accept incoming connection\n" );
return;
}
addConnection( serv, sock );
}
/* -1 on failure, 0 on success */
int parseMatchSpec( const Config *conf,
ServerState *serv,
const char *spec,
LLPoolEntry *connEntry,
Match *match )
{
uint32_t rngSeed;
int pos, t, p;
LLPoolEntry *entry;
char tag[ READBUF_LEN ];
char name[ READBUF_LEN ];
pos = 0;
if( sscanf( &spec[ pos ], " %s%n", name, &t ) < 1 ) {
return -1;
}
pos += t;
entry = findGame( conf, name );
if( entry == NULL ) {
return -1;
}
match->gameConf = (GameConfig *)LLPoolGetItem( entry );
if( sscanf( &spec[ pos ],
" %d %s %"SCNu32" %n",
&match->numRuns,
tag,
&rngSeed,
&t ) < 3 ) {
return -1;
}
pos += t;
if( match->numRuns < 0 || match->numRuns > match->gameConf->maxMatchRuns ) {
return -1;
}
/* make sure tag has no characters in it */
if( strchr( tag, '/' ) != NULL ) {
return -1;
}
/* get bots */
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
/* get the name */
if( sscanf( &spec[ pos ], " %s%n", name, &t ) < 1 ) {
return -1;
}
pos += t;
/* translate the name into an index */
if( !strcmp( name, "LOCAL" ) ) {
match->players[ p ].isNetworkPlayer = 1;
match->players[ p ].entry = connEntry;
} else {
match->players[ p ].isNetworkPlayer = 0;
match->players[ p ].entry = findBot( match->gameConf, name );
if( match->players[ p ].entry == NULL ) {
return -1;
}
}
}
match->tag = strdup( tag );
match->rngSeed = rngSeed;
if( rngSeed ) {
init_genrand( &match->rng, rngSeed );
if( match->numRuns == 1 ) {
match->useRngForSeed = 0;
} else {
match->useRngForSeed = 1;
}
} else {
init_genrand( &match->rng, genrand_int32( &serv->rng ) );
}
return 0;
}
void writeHelpMessage( int fd )
{
int r;
r = write( fd, "HELP - this message\n", 20 );
r = write( fd, "GAMES - list available games and players\n", 41 );
r = write( fd, "QSTAT - show the current queue\n", 31 );
r = write( fd, "RUNMATCHES game #runs tag rngSeed player ... - submit match request\n", 68 );
r = write( fd, " - Player order decides match seating\n", 39 );
r = write( fd, " - \"LOCAL\" player runs the bm_widget agent (bot_command)\n", 60 );
}
void writeGameList( const Config *conf, int fd )
{
int r;
LLPoolEntry *cur, *botCur;
char line[ READBUF_LEN ];
for( cur = LLPoolFirstEntry( conf->games );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
GameConfig *game = (GameConfig *)LLPoolGetItem( cur );
r = snprintf( line, sizeof( line ), "\n%s\n", game->gameFile );
assert( r > 0 );
r = write( fd, line, r );
for( botCur = LLPoolFirstEntry( game->bots );
botCur != NULL; botCur = LLPoolNextEntry( botCur ) ) {
BotSpec *bot = (BotSpec *)LLPoolGetItem( botCur );
r = snprintf( line, sizeof( line ), " %s\n", bot->name );
assert( r > 0 );
r = write( fd, line, r );
}
}
}
void writeQueueStatus( const Config *conf, const ServerState *serv, int fd )
{
int r;
LLPoolEntry *cur;
char line[ READBUF_LEN * 4 ];
if( serv->matches->numEntries == 0 ) {
r = write( fd, "Queue empty\n", 12 );
}
for( cur = LLPoolFirstEntry( serv->matches );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
Match *match = (Match *)LLPoolGetItem( cur );
r = snprintf( line,
sizeof( line ),
"%s %s %s * %d %s\n",
match->user->name,
match->tag,
match->gameConf->gameFile,
match->numRuns,
match->isRunning ? "R" : "Q" );
assert( r > 0 );
r = write( fd, line, r );
}
}
void handleConnection( Config *conf, ServerState *serv,
LLPoolEntry *connEntry )
{
int r;
Connection *conn = (Connection *)LLPoolGetItem( connEntry );
char line[ READBUF_LEN ];
while( ( r = getLine( conn->connBuf, READBUF_LEN, line, 0 ) ) >= 0 ) {
if( r == 0 ) {
closeConnection( serv, connEntry );
return;
}
if( conn->status == STATUS_UNVALIDATED ) {
UserSpec *user;
user = validateLogon( conf, line );
if( user == NULL ) {
/* couldn't authenticate */
r = write( conn->connBuf->fd, "BAD LOGON\n", 10 );
fprintf( stderr, "BM_ERROR: connection failed to log in\n" );
closeConnection( serv, connEntry );
return;
}
/* send an okay message */
r = write( conn->connBuf->fd, "LOGON OKAY - type help for commands\n", 36 );
/* connection status is now okay */
conn->user = user;
conn->status = STATUS_OKAY;
return;
}
if( !strncasecmp( line, "HELP", 4 ) ) {
writeHelpMessage( conn->connBuf->fd );
} else if( !strncasecmp( line, "GAMES", 5 ) ) {
writeGameList( conf, conn->connBuf->fd );
} else if( !strncasecmp( line, "QSTAT", 5 ) ) {
writeQueueStatus( conf, serv, conn->connBuf->fd );
} else if( !strncasecmp( line, "RUNMATCHES", 10 ) ) {
Match match;
if( parseMatchSpec( conf, serv, &line[ 10 ], connEntry, &match ) < 0 ) {
fprintf( stderr, "BM_ERROR: bad RUNMATCHES command: %s", line );
r = write( conn->connBuf->fd, "BAD RUNMATCHES COMMAND\n", 23 );
return;
}
match.user = ( (Connection *)LLPoolGetItem( connEntry ) )->user;
match.isRunning = 0;
gettimeofday( &match.queueTime, NULL );
LLPoolAddItem( serv->matches, &match );
return;
} else {
r = write( conn->connBuf->fd, "UNKNOWN\n", 8 );
return;
}
}
}
int timeIsEarlier( struct timeval *a, struct timeval *b )
{
if( a->tv_sec < b->tv_sec ) {
return 1;
} else if( a->tv_sec == b->tv_sec
&& a->tv_usec < b->tv_usec ) {
return 1;
}
return 0;
}
/* how many bots will match start? */
int botsInMatch( const Match *match )
{
int p, num;
num = 0;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( !match->players[ p ].isNetworkPlayer ) {
++num;
}
}
return num;
}
void startDealer( const Config *conf,
const Match *match,
MatchJob *job,
const uint32_t rngSeed )
{
int stdoutPipe[ 2 ], p, arg;
char handsString[ 16 ], rngString[ 16 ];
char startupTimeoutString[ 16 ], responseTimeoutString[ 16 ];
char handTimeoutString[ 16 ], avgHandTimeString[ 16 ];
char *argv[ MAX_PLAYERS + 64 ];
if( pipe( stdoutPipe ) < 0 ) {
fprintf( stderr, "BM_ERROR: could not create pipe for new dealer\n" );
exit( EXIT_FAILURE );
}
job->dealerPID = fork();
if( job->dealerPID < 0 ) {
fprintf( stderr, "BM_ERROR: fork() failed\n" );
exit( EXIT_FAILURE );
}
if( !job->dealerPID ) {
/* child runs the dealer command */
int stderrfd;
char tag[ READBUF_LEN ];
snprintf( tag, sizeof( tag ), "%s/%s.stderr", BM_LOGDIR, job->tag );
stderrfd = open( tag, O_WRONLY | O_APPEND | O_CREAT, 0644 );
if( stderrfd < 0 ) {
fprintf( stderr,
"BM_ERROR: could not create error log %s\n",
tag );
exit( EXIT_FAILURE );
}
dup2( stderrfd, 2 );
/* change stdout to be the write end of the pipe */
close( stdoutPipe[ 0 ] );
dup2( stdoutPipe[ 1 ], 1 );
arg = 0;
argv[ arg ] = BM_DEALER;
++arg;
snprintf( tag, sizeof( tag ), "%s/%s", BM_LOGDIR, job->tag );
argv[ arg ] = tag;
++arg;
argv[ arg ] = match->gameConf->gameFile;
++arg;
snprintf( handsString,
sizeof( handsString ),
"%"PRIu32,
match->gameConf->matchHands );
argv[ arg ] = handsString;
++arg;
snprintf( rngString, sizeof( rngString ), "%"PRIu32, rngSeed );
argv[ arg ] = rngString;
++arg;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( match->players[ p ].isNetworkPlayer ) {
argv[ arg ]
= ( (Connection *)LLPoolGetItem( match->players[ p ].entry ) )
->user->name;
} else {
argv[ arg ]
= ( (BotSpec *)LLPoolGetItem( match->players[ p ].entry ) )->name;
}
++arg;
}
if( conf->startupTimeoutSecs ) {
argv[ arg ] = "--start_timeout";
++arg;
snprintf( startupTimeoutString,
sizeof( startupTimeoutString ),
"%d",
(int)conf->startupTimeoutSecs * 1000 );
argv[ arg ] = startupTimeoutString;
++arg;
}
/* Add maximum per action timeout argument */
argv[ arg ] = "--t_response";
++arg;
snprintf( responseTimeoutString,
sizeof( responseTimeoutString ),
"%d",
(int)conf->responseTimeoutSecs * 1000 );
argv[ arg ] = responseTimeoutString;
++arg;
/* Add maximum per hand timeout argument */
argv[ arg ] = "--t_hand";
++arg;
snprintf( handTimeoutString,
sizeof( handTimeoutString ),
"%d",
(int)conf->handTimeoutSecs * 1000 );
argv[ arg ] = handTimeoutString;
++arg;
/* Add average per hand time argument */
argv[ arg ] = "--t_per_hand";
++arg;
snprintf( avgHandTimeString,
sizeof( avgHandTimeString ),
"%d",
(int)conf->avgHandTimeSecs * 1000 );
argv[ arg ] = avgHandTimeString;
++arg;
argv[ arg ] = "-q";
++arg;
/* Restore the appending behaviour so multiple matches get appended into
* the same log file */
argv[ arg ] = "-a";
++arg;
argv[ arg ] = NULL;
execv( BM_DEALER, argv );
fprintf( stderr, "BM_ERROR: could not start dealer\n" );
exit( EXIT_FAILURE );
}
/* parent has to talk to child to get ports */
ssize_t r;
int pos, t;
fd_set readfds;
struct timeval timeout;
char portString[ READBUF_LEN ];
close( stdoutPipe[ 1 ] );
timeout.tv_sec = BM_DEALER_WAIT_SECS;
timeout.tv_usec = 0;
FD_ZERO( &readfds );
FD_SET( stdoutPipe[ 0 ], &readfds );
if( select( stdoutPipe[ 0 ] + 1, &readfds, NULL, NULL, &timeout ) < 1 ) {
fprintf( stderr,
"BM_ERROR: timed out waiting for port string from dealer\n" );
exit( EXIT_FAILURE );
}
r = read( stdoutPipe[ 0 ], portString, READBUF_LEN );
if( r <= 0 || portString[ r - 1 ] != '\n' ) {
fprintf( stderr, "BM_ERROR: could not read port string from dealer\n" );
exit( EXIT_FAILURE );
}
portString[ r ] = 0;
/* parse the port string */
pos = 0;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( sscanf( &portString[ pos ],
" %"SCNu16"%n",
&job->ports[ p ],
&t ) < 1 ) {
fprintf( stderr,
"BM_ERROR: could not get port for player %d from dealer\n",
p + 1 );
exit( EXIT_FAILURE );
}
pos += t;
}
}
pid_t startBot( const ServerState *serv,
const BotSpec *bot,
const uint16_t port,
const int botPosition )
{
pid_t pid;
pid = fork();
if( pid < 0 ) {
fprintf( stderr, "BM_ERROR: fork() failed\n" );
exit( EXIT_FAILURE );
}
if( !pid ) {
/* child runs the bot command */
char portString[ 8 ];
char posString[ 16 ];
snprintf( portString, sizeof( portString ), "%"PRIu16, port );
snprintf( posString, sizeof( posString ), "%d", botPosition );
/* throw away bot output */
dup2( serv->devnullfd, 1 );
dup2( serv->devnullfd, 2 );
execl( bot->command,
bot->command,
serv->hostname,
portString,
posString,
NULL );
fprintf( stderr, "BM_ERROR: could not start bot %s\n", bot->command );
exit( EXIT_FAILURE );
}
return pid;
}
int sendStartMessage( const ServerState *serv,
const MatchJob *job,
const Connection *conn,
const uint16_t port )
{
int len;
char msg[ strlen( serv->hostname ) + 12 + READBUF_LEN ];
len = snprintf( msg, sizeof( msg ), "# RUNNING %s\n", job->tag );
assert( len > 0 );
if( write( conn->connBuf->fd, msg, len ) < len ) {
fprintf( stderr, "BM_ERROR: short write to connection\n" );
return -1;
}
len = snprintf( msg,
sizeof( msg ),
"RUN %s %"PRIu16"\n",
serv->hostname, port );
assert( len > 0 );
if( write( conn->connBuf->fd, msg, len ) < len ) {
fprintf( stderr, "BM_ERROR: short write to connection\n" );
return -1;
}
return 0;
}
MatchJob runMatchJob( const Config *conf,
const ServerState *serv,
LLPoolEntry *matchEntry,
const uint32_t rngSeed )
{
int p, botPosition;
MatchJob job;
Match *match = (Match *)LLPoolGetItem( matchEntry );
char tag[ READBUF_LEN ];
job.matchEntry = matchEntry;
/* make the tag from the match tag */
snprintf( tag, sizeof( tag ), "%s.%s", match->user->name, match->tag );
job.tag = strdup( tag );
/* initialise all PIDs to 0 */
job.dealerPID = 0;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
job.botPID[ p ] = 0;
}
/* start the dealer */
startDealer( conf, match, &job, rngSeed );
/* deal with all the players */
botPosition = 0;
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( match->players[ p ].isNetworkPlayer ) {
/* send message with port to network player to start up */
Connection *conn = (Connection*)LLPoolGetItem( match->players[ p ].entry );
if( sendStartMessage( serv, &job, conn, job.ports[ p ] ) < 0 ) {
/* abort the job... */
fprintf( stderr, "BM_ERROR: aborting job\n" );
kill( job.dealerPID, SIGTERM );
while( p > 0 ) {
--p;
if( job.botPID[ p ] ) {
kill( job.botPID[ p ], SIGTERM );
}
}
return job;
}
} else {
/* start up bot */
job.botPID[ p ]
= startBot( serv,
(BotSpec *)LLPoolGetItem( match->players[ p ].entry ),
job.ports[ p ],
botPosition );
++botPosition;
}
}
return job;
}
int startMatchJob( const Config *conf, ServerState *serv )
{
int running;
LLPoolEntry *cur, *next, *best;
Match *curMatch, *bestMatch;
MatchJob job;
/* automatically done adding things if we've got no more matches */
if( serv->matches->numEntries == 0 ) {
return 0;
}
/* how many bots are currently running */
running = 0;
for( cur = LLPoolFirstEntry( serv->jobs );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
MatchJob *job = (MatchJob *)LLPoolGetItem( cur );
running += botsInMatch( (Match*)LLPoolGetItem( job->matchEntry ) );
}
/* pick the best match to start */
best = 0;
bestMatch = 0;
for( cur = LLPoolFirstEntry( serv->matches ); cur != NULL; cur = next ) {
next = LLPoolNextEntry( cur );
curMatch = (Match *)LLPoolGetItem( cur );
if( curMatch->isRunning ) {
continue;
}
if( curMatch->numRuns <= 0 ) {
/* match is finished - clean it up */
free( curMatch->tag );
LLPoolRemoveEntry( serv->matches, cur );
continue;
}
if( curMatch->gameConf->maxRunningJobs
&& curMatch->gameConf->curRunningJobs
>= curMatch->gameConf->maxRunningJobs ) {
/* cur refers to a match in a game which is currently too busy */
continue;
}
if( best == 0
|| timeIsEarlier( &curMatch->user->waitStart,
&bestMatch->user->waitStart )
|| ( !timeIsEarlier( &bestMatch->user->waitStart,
&curMatch->user->waitStart )
&& timeIsEarlier( &curMatch->queueTime,
&bestMatch->queueTime ) ) ) {
best = cur;
bestMatch = curMatch;
}
}
/* return failure if we couldn't find a runnable job */
if( best == NULL ) {
return 0;
}
/* check if we have the space to run the bots */
if( conf->maxRunningBots
&& botsInMatch( bestMatch ) + running > conf->maxRunningBots ) {
return 0;
}
/* create the job */
job = runMatchJob( conf,
serv,
best,
bestMatch->useRngForSeed
? genrand_int32( &bestMatch->rng )
: bestMatch->rngSeed );
assert( job.dealerPID );
LLPoolAddItem( serv->jobs, &job );
/* update status about running jobs */
++( bestMatch->gameConf->curRunningJobs );
bestMatch->isRunning = 1;
/* update the user */
gettimeofday( &bestMatch->user->waitStart, NULL );
/* update the match */
--bestMatch->numRuns;
gettimeofday( &bestMatch->queueTime, NULL );
return 1;
}
void initServerState( const Config *conf, ServerState *serv )
{
struct addrinfo hints, *info;
uint16_t port;
int hnm, r;
char *hn;
char ipstr[ INET6_ADDRSTRLEN ];
serv->conns = newLLPool( sizeof( Connection ) );
serv->matches = newLLPool( sizeof( Match ) );
serv->jobs = newLLPool( sizeof( MatchJob ) );
/* create the socket clients will connect to */
port = conf->port;
serv->listenSocket = getListenSocket( &port );
if( serv->listenSocket < 0 ) {
fprintf( stderr, "BM_ERROR: could not open socket for listening\n" );
exit( EXIT_FAILURE );
}
printf( "starting server on port %"PRIu16"\n", conf->port );
init_genrand( &serv->rng, time( NULL ) );
hnm = sysconf( _SC_HOST_NAME_MAX );
hn = (char*)malloc( hnm );
assert( hn != 0 );
if( gethostname( hn, hnm + 1 ) < 0 ) {
fprintf( stderr, "BM_ERROR: could not get hostname\n" );
exit( EXIT_FAILURE );
}
memset( &hints, 0, sizeof( hints ) );
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if( ( r = getaddrinfo( hn, NULL, &hints, &info ) ) != 0 ) {
fprintf( stderr,
"BM_ERROR: could not get address info for host %s\n",
hn );
exit( 1 );
}
free( hn );
/* Get an address for the server */
void *addr;
/* get the pointer to the address itself,
* different fields in IPv4 and IPv6: */
if ( info->ai_family == AF_INET ) {
/* IPv4 */
struct sockaddr_in *ipv4 = ( struct sockaddr_in * ) info->ai_addr;
addr = &( ipv4->sin_addr );
} else {
/* IPv6 */
struct sockaddr_in6 *ipv6 = ( struct sockaddr_in6 * ) info->ai_addr;
addr = &( ipv6->sin6_addr );
}
/* convert the IP to a string and store it:*/
inet_ntop( info->ai_family, addr, ipstr, sizeof( ipstr ) );
serv->hostname = strdup( ipstr );
freeaddrinfo( info ); /* free the linked list */
serv->devnullfd = open( "/dev/null", O_WRONLY );
if( serv->devnullfd < 0 ) {
fprintf( stderr, "BM_ERROR: could not open /dev/null\n" );
exit( EXIT_FAILURE );
}
}
int checkIfJobFinished( MatchJob *job )
{
int status, r, p, allDone;
Match *match = (Match *)LLPoolGetItem( job->matchEntry );
allDone = 1;
if( job->dealerPID ) {
r = waitpid( job->dealerPID, &status, WNOHANG );
if( r < 0 ) {
fprintf( stderr, "BM_ERROR: could not wait on child\n" );
exit( EXIT_FAILURE );
}
if( r == job->dealerPID ) {
job->dealerPID = 0;
} else {
allDone = 0;
}
}
for( p = 0; p < match->gameConf->game->numPlayers; ++p ) {
if( job->botPID[ p ] == 0 ) {
continue;
}
r = waitpid( job->botPID[ p ], &status, WNOHANG );
if( r < 0 ) {
fprintf( stderr, "BM_ERROR: could not wait on child\n" );
exit( EXIT_FAILURE );
}
if( r == job->botPID[ p ] ) {
job->botPID[ p ] = 0;
} else {
allDone = 0;
}
}
return allDone;
}
void finishedJob( ServerState *serv, LLPoolEntry *jobEntry )
{
MatchJob *job = (MatchJob *)LLPoolGetItem( jobEntry );
Match *match = (Match *)LLPoolGetItem( job->matchEntry );
free( job->tag );
--( match->gameConf->curRunningJobs );
match->isRunning = 0;
LLPoolRemoveEntry( serv->jobs, jobEntry );
}
int main( int argc, char **argv )
{
Config conf;
ServerState serv;
int maxfd;
fd_set readfds;
LLPoolEntry *cur, *next;
struct timeval tv;
if( argc < 2 ) {
printUsage( stderr );
exit( EXIT_FAILURE );
}
/* Ignore SIGPIPE. It seems that SIGPIPE can be raised when the underlying
* IO fails with a SIGPIPE. Unfortunately this causes the entire benchmark
* server to crash and jobs are lost. Ignore the signal to avoid death */
/* ???: May also need to catch SIGCHLD */
signal( SIGPIPE, SIG_IGN );
/* use the config file */
setDefaults( &conf );
readConfig( argv[ 1 ], &conf );
/* initialise server state */
initServerState( &conf, &serv );
/* main I/O loop */
while( 1 ) {
/* clean up any finished jobs */
for( cur = LLPoolFirstEntry( serv.jobs ); cur != NULL; cur = next ) {
next = LLPoolNextEntry( cur );
MatchJob *job = (MatchJob *)LLPoolGetItem( cur );
if( checkIfJobFinished( job ) ) {
finishedJob( &serv, cur );
}
}
/* clean up any closed connections */
for( cur = LLPoolFirstEntry( serv.conns ); cur != NULL; cur = next ) {
next = LLPoolNextEntry( cur );
if( ( (Connection *)LLPoolGetItem( cur ) )->status == STATUS_CLOSED ) {
LLPoolRemoveEntry( serv.conns, cur );
}
}
/* start jobs, up to the maximum */
while( startMatchJob( &conf, &serv ) );
/* wait for input */
FD_ZERO( &readfds );
FD_SET( serv.listenSocket, &readfds );
maxfd = serv.listenSocket;
tv.tv_sec = BM_MAX_IOWAIT_SECS;
tv.tv_usec = 0;
for( cur = LLPoolFirstEntry( serv.conns );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
Connection *conn = (Connection *)LLPoolGetItem( cur );
FD_SET( conn->connBuf->fd, &readfds );
if( conn->connBuf->fd > maxfd ) {
maxfd = conn->connBuf->fd;
}
}
if( select( maxfd + 1, &readfds, NULL, NULL, &tv ) < 0 ) {
fprintf( stderr, "BM_ERROR: select failed\n" );
exit( -1 );
}
/* process anything that's happened */
if( FD_ISSET( serv.listenSocket, &readfds ) ) {
handleListenSocket( &conf, &serv );
}
for( cur = LLPoolFirstEntry( serv.conns );
cur != NULL; cur = LLPoolNextEntry( cur ) ) {
Connection *conn = (Connection *)LLPoolGetItem( cur );
if( FD_ISSET( conn->connBuf->fd, &readfds ) ) {
handleConnection( &conf, &serv, cur );
}
}
}
close( serv.listenSocket );
return EXIT_SUCCESS;
}
================================================
FILE: ACPCServer/bm_server.config
================================================
# port to connect to the server
port 54000
# maxmimum number of simultaneously locally running bots
# 0 disables
maxRunningBots 0
# maximum time in seconds to wait for clients to connect when starting a match
startupTimeoutSecs 1000
# maximum time in seconds to wait for clients to act during a match
responseTimeoutSecs 60000
# maximum time in seconds allowed for a client to play a given hand
handTimeoutSecs 210000
# average time in seconds allowed for a client to spend on each hand
avgHandTimeSecs 700
# heads up limit Texas Hold'em
game holdem.limit.2p.reverse_blinds.game {
# maximum number of times a match can be run with a single player request
maxMatchRuns 10
# maxmimum number of simultaneously running matches using this game
# 0 disables
maxRunningJobs 1
# number of hands in a match
matchHands 5000
# bot botName botStartupScript
# botStartupScript is run with 3 args: server name, port, local position
# local postion indicates which LOCAL bot this is (index starting from 0)
# This is useful when determining which of multiple machines to run on
bot testBot example_player.limit.2p.sh
}
# heads up limit Texas Hold'em
game holdem.nolimit.2p.reverse_blinds.game {
# maximum number of times a match can be run with a single player request
maxMatchRuns 10
# maxmimum number of simultaneously running matches using this game
# 0 disables
maxRunningJobs 1
# number of hands in a match
matchHands 5000
# bot botName botStartupScript
# botStartupScript is run with 3 args: server name, port, local position
# local postion indicates which LOCAL bot this is (index starting from 0)
# This is useful when determining which of multiple machines to run on
bot testBot example_player.nolimit.2p.sh
}
# heads up limit Texas Hold'em
game holdem.limit.3p.game {
# maximum number of times a match can be run with a single player request
maxMatchRuns 10
# maxmimum number of simultaneously running matches using this game
# 0 disables
maxRunningJobs 1
# number of hands in a match
matchHands 5000
# bot botName botStartupScript
# botStartupScript is run with 3 args: server name, port, local position
# local postion indicates which LOCAL bot this is (index starting from 0)
# This is useful when determining which of multiple machines to run on
bot testBot example_player.limit.3p.sh
}
# Users authorized to run jobs on the benchmark (user name pass)
user neil test
================================================
FILE: ACPCServer/bm_widget.c
================================================
/*
Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
*/
#include <stdlib.h>
#include <stdio.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/wait.h>
#include <errno.h>
#include "net.h"
#define ARG_SERVERNAME 1
#define ARG_SERVERPORT 2
#define ARG_BOT_COMMAND 3
#define ARG_NUM_ARGS 4
static void printUsage( FILE *file )
{
fprintf( file, "usage: bm_widget bm_hostname bm_port bot_command\n" );
fprintf( file, " bot_command: agent executable, passed \"hostname port\"\n");
}
/* 0 on success, -1 on failure */
int login( char *user, char *passwd, FILE *conn )
{
if( fprintf( conn, "%s %s\n", user, passwd ) < 0 ) {
return -1;
}
fflush( conn );
return 0;
}
int main( int argc, char **argv )
{
int sock, i;
pid_t childPID;
uint16_t port;
ReadBuf *fromUser, *fromServer;
fd_set readfds;
char line[ READBUF_LEN ];
if( argc < ARG_NUM_ARGS ) {
printUsage( stderr );
exit( EXIT_FAILURE );
}
/* connect to the server */
if( sscanf( argv[ ARG_SERVERPORT ], "%"SCNu16, &port ) < 1 ) {
fprintf( stderr, "ERROR: invalid port %s\n", argv[ ARG_SERVERPORT ] );
exit( EXIT_FAILURE );
}
sock = connectTo( argv[ ARG_SERVERNAME ], port );
if( sock < 0 ) {
exit( EXIT_FAILURE );
}
// EJ additions 9/3/2012
// Turn on keep-alive for socket connection with more frequent checking
// than the Linux default. What I've observed is that if a socket
// connection is idle for long enough it gets dropped. This only
// happens for some users.
int on = 1;
if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
#ifdef __linux__
// Not sure what this should be
int num_before_failure = 2;
if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &num_before_failure,
sizeof(num_before_failure)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
// First check after 60 seconds
int initial_secs = 60;
if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &initial_secs,
sizeof(initial_secs)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
// Thereafter, also check every 60 seconds
int interval_secs = 60;
if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &interval_secs,
sizeof(interval_secs)) == -1) {
fprintf( stderr, "ERROR: setsockopt failed; errno %i\n", errno );
exit( EXIT_FAILURE );
}
#endif
/* set up read buffers */
fromUser = createReadBuf( 0 );
fromServer = createReadBuf( sock );
printf( "Log in with 'user password'\n" );
fflush( stdout );
/* main loop */
while( 1 ) {
/* clean up any children */
while( waitpid( -1, NULL, WNOHANG ) > 0 );
/* wait for input */
FD_ZERO( &readfds );
FD_SET( 0, &readfds );
FD_SET( sock, &readfds );
i = select( sock + 1, &readfds, NULL, NULL, NULL );
if( i < 0 ) {
fprintf( stderr, "ERROR: select failed\n" );
exit( EXIT_FAILURE );
}
if( i == 0 ) {
/* nothing ready - shouldn't happen without timeout */
continue;
}
/* handle user input by passing it directly to server */
if( FD_ISSET( 0, &readfds ) ) {
/* get the input */
while( ( i = getLine( fromUser, READBUF_LEN, line, 0 ) ) >= 0 ) {
if( i == 0 ) {
/* Done! */
exit( EXIT_SUCCESS );
}
/* write to server */
if( write( sock, line, i ) < 0 ) {
fprintf( stderr, "ERROR: failed while sending to server\n" );
exit( EXIT_FAILURE );
}
}
}
/* handle server messages */
if( FD_ISSET( sock, &readfds ) ) {
/* get the input */
while( ( i = getLine( fromServer, READBUF_LEN, line, 0 ) ) >= 0 ) {
if( i == 0 ) {
fprintf( stderr, "ERROR: server closed connection?\n" );
exit( EXIT_FAILURE );
}
/* check for server commands */
if( strncasecmp( line, "run ", 4 ) == 0 ) {
/* split the rest of the line into name ' ' port */
for( i = 4; line[ i ]; ++i ) {
if( line[ i ] == ' ' ) {
/* found the separator */
line[ i ] = 0;
break;
}
}
printf( "starting match %s:%s", &line[ 4 ], &line[ i + 1 ] );
fflush( stdout );
/* run `command machine port` */
childPID = fork();
if( childPID < 0 ) {
fprintf( stderr, "ERROR: fork() failed\n" );
exit( EXIT_FAILURE );
}
if( childPID == 0 ) {
/* child runs the command */
execl( argv[ ARG_BOT_COMMAND ],
argv[ ARG_BOT_COMMAND ],
&line[ 4 ],
&line[ i + 1 ],
NULL );
fprintf( stderr,
"ERROR: could not run %s\n",
argv[ ARG_BOT_COMMAND ] );
exit( EXIT_FAILURE );
}
} else {
/* just a message, print it out */
if( fwrite( line, 1, i, stdout ) < 0 ) {
fprintf( stderr, "ERROR: failed while printing server message\n" );
exit( EXIT_FAILURE );
}
fflush( stdout );
}
}
}
}
return EXIT_SUCCESS;
}
================================================
FILE: ACPCServer/dealer.c
================================================
/*
Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
*/
#include <stdlib.h>
#include <stdio.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <getopt.h>
#include "game.h"
#include "net.h"
/* the ports for players to connect to will be printed on standard out
(in player order)
if log file is enabled, matchName.log will contain finished states
and values, followed by the final total values for each player
if transaction file is enabled, matchName.tlog will contain a list
of actions taken and timestamps that is sufficient to recreate an
interrupted match
if the quiet option is not enabled, standard error will print out
the messages sent to and receieved from the players
the final total values for each player will be printed to both
standard out and standard error
exit value is EXIT_SUCCESS if the match was a success,
or EXIT_FAILURE on any failure */
#define DEFAULT_MAX_INVALID_ACTIONS UINT32_MAX
#define DEFAULT_MAX_RESPONSE_MICROS 6000000000
#define DEFAULT_MAX_USED_HAND_MICROS 6000000000
#define DEFAULT_MAX_USED_PER_HAND_MICROS 70000000
typedef struct {
uint32_t maxInvalidActions;
uint64_t maxResponseMicros;
uint64_t maxUsedHandMicros;
uint64_t maxUsedMatchMicros;
uint32_t numInvalidActions[ MAX_PLAYERS ];
uint64_t usedHandMicros[ MAX_PLAYERS ];
uint64_t usedMatchMicros[ MAX_PLAYERS ];
} ErrorInfo;
static void printUsage( FILE *file, int verbose )
{
fprintf( file, "usage: dealer matchName gameDefFile #Hands rngSeed p1name p2name ... [options]\n" );
fprintf( file, " -f use fixed dealer button at table\n" );
fprintf( file, " -l/L disable/enable log file - enabled by default\n" );
fprintf( file, " -p player1_port,player2_port,... [default is random]\n" );
fprintf( file, " -q only print errors, warnings, and final value to stderr\n" );
fprintf( file, " -t/T disable/enable transaction file - disabled by default\n" );
fprintf( file, " -a append to log/transaction files - disabled by default\n" );
fprintf( file, " --t_response [milliseconds] maximum time per response\n" );
fprintf( file, " --t_hand [milliseconds] maximum player time per hand\n" );
fprintf( file, " --t_per_hand [milliseconds] maximum average player time for match\n" );
fprintf( file, " --start_timeout [milliseconds] maximum time to wait for players to connect\n" );
fprintf( file, " <0 [default] is no timeout\n" );
}
/* returns >= 0 on success, -1 on error */
static int scanPortString( const char *string,
uint16_t listenPort[ MAX_PLAYERS ] )
{
int c, r, p;
c = 0;
for( p = 0; p < MAX_PLAYERS; ++p ) {
if( string[ c ] == 0 ) {
/* finished parsing the string */
break;
}
if( p ) {
/* look for separator */
if( string[ c ] != ',' ) {
/* numbers should be comma separated */
return -1;
}
++c;
}
if( sscanf( &string[ c ], "%"SCNu16"%n", &listenPort[ p ], &r ) < 1 ) {
/* couldn't get a number */
return -1;
}
c += r;
}
return 0;
}
static void initErrorInfo( const uint32_t maxInvalidActions,
const uint64_t maxResponseMicros,
const uint64_t maxUsedHandMicros,
const uint64_t maxUsedMatchMicros,
ErrorInfo *info )
{
int s;
info->maxInvalidActions = maxInvalidActions;
info->maxResponseMicros = maxResponseMicros;
info->maxUsedHandMicros = maxUsedHandMicros;
info->maxUsedMatchMicros = maxUsedMatchMicros;
for( s = 0; s < MAX_PLAYERS; ++s ) {
info->numInvalidActions[ s ] = 0;
info->usedHandMicros[ s ] = 0;
info->usedMatchMicros[ s ] = 0;
}
}
/* update the number of invalid actions for seat
returns >= 0 if match should continue, -1 for failure */
static int checkErrorInvalidAction( const uint8_t seat, ErrorInfo *info )
{
++( info->numInvalidActions[ seat ] );
if( info->numInvalidActions[ seat ] > info->maxInvalidActions ) {
return -1;
}
return 0;
}
/* update the time used by seat
returns >= 0 if match should continue, -1 for failure */
static int checkErrorTimes( const uint8_t seat,
const struct timeval *sendTime,
const struct timeval *recvTime,
ErrorInfo *info )
{
uint64_t responseMicros;
/* calls to gettimeofday can return earlier times on later calls :/ */
if( recvTime->tv_sec < sendTime->tv_sec
|| ( recvTime->tv_sec == sendTime->tv_sec
&& recvTime->tv_usec < sendTime->tv_usec ) ) {
return 0;
}
/* figure out how many microseconds the response took */
responseMicros = ( recvTime->tv_sec - sendTime->tv_sec ) * 1000000
+ recvTime->tv_usec - sendTime->tv_usec;
/* update usage counts */
info->usedHandMicros[ seat ] += responseMicros;
info->usedMatchMicros[ seat ] += responseMicros;
/* check time used for the response */
if( responseMicros > info->maxResponseMicros ) {
return -1;
}
/* check time used in the current hand */
if( info->usedHandMicros[ seat ] > info->maxUsedHandMicros ) {
return -1;
}
/* check time used in the entire match */
if( info->usedMatchMicros[ seat ] > info->maxUsedMatchMicros ) {
return -1;
}
return 0;
}
/* note that there is a new hand
returns >= 0 if match should continue, -1 for failure */
static int checkErrorNewHand( const Game *game, ErrorInfo *info )
{
uint8_t p;
for( p = 0; p < game->numPlayers; ++p ) {
info->usedHandMicros[ p ] = 0;
}
return 0;
}
static uint8_t seatToPlayer( const Game *game, const uint8_t player0Seat,
const uint8_t seat )
{
return ( seat + game->numPlayers - player0Seat ) % game->numPlayers;
}
static uint8_t playerToSeat( const Game *game, const uint8_t player0Seat,
const uint8_t player )
{
return ( player + player0Seat ) % game->numPlayers;
}
/* returns >= 0 if match should continue, -1 for failure */
static int sendPlayerMessage( const Game *game, const MatchState *state,
const int quiet, const uint8_t seat,
const int seatFD, struct timeval *sendTime )
{
int c;
char line[ MAX_LINE_LEN ];
/* prepare the message */
c = printMatchState( game, state, MAX_LINE_LEN, line );
if( c < 0 || c > MAX_LINE_LEN - 3 ) {
/* message is too long */
fprintf( stderr, "ERROR: state message too long\n" );
return -1;
}
line[ c ] = '\r';
line[ c + 1 ] = '\n';
line[ c + 2 ] = 0;
c += 2;
/* send it to the player and flush */
if( write( seatFD, line, c ) != c ) {
/* couldn't send the line */
fprintf( stderr, "ERROR: could not send state to seat %"PRIu8"\n",
seat + 1 );
return -1;
}
/* note when we sent the message */
gettimeofday( sendTime, NULL );
/* log the message */
if( !quiet ) {
fprintf( stderr, "TO %d at %zu.%.06zu %s", seat + 1,
sendTime->tv_sec, sendTime->tv_usec, line );
}
return 0;
}
/* returns >= 0 if action/size has been set to a valid action
returns -1 for failure (disconnect, timeout, too many bad actions, etc) */
static int readPlayerResponse( const Game *game,
const MatchState *state,
const int quiet,
const uint8_t seat,
const struct timeval *sendTime,
ErrorInfo *errorInfo,
ReadBuf *readBuf,
Action *action,
struct timeval *recvTime )
{
int c, r;
MatchState tempState;
char line[ MAX_LINE_LEN ];
while( 1 ) {
/* read a line of input from player */
struct timeval start;
gettimeofday( &start, NULL );
if( getLine( readBuf, MAX_LINE_LEN, line,
errorInfo->maxResponseMicros ) <= 0 ) {
/* couldn't get any input from player */
struct timeval after;
gettimeofday( &after, NULL );
uint64_t micros_spent =
(uint64_t)( after.tv_sec - start.tv_sec ) * 1000000
+ ( after.tv_usec - start.tv_usec );
fprintf( stderr, "ERROR: could not get action from seat %"PRIu8"\n",
seat + 1 );
// Print out how much time has passed so we can see if this was a
// timeout as opposed to some other sort of failure (e.g., socket
// closing).
fprintf( stderr, "%.1f seconds spent waiting; timeout %.1f\n",
micros_spent / 1000000.0,
errorInfo->maxResponseMicros / 1000000.0);
return -1;
}
/* note when the message arrived */
gettimeofday( recvTime, NULL );
/* log the response */
if( !quiet ) {
fprintf( stderr, "FROM %d at %zu.%06zu %s", seat + 1,
recvTime->tv_sec, recvTime->tv_usec, line );
}
/* ignore comments */
if( line[ 0 ] == '#' || line[ 0 ] == ';' ) {
continue;
}
/* check for any timeout issues */
if( checkErrorTimes( seat, sendTime, recvTime, errorInfo ) < 0 ) {
fprintf( stderr, "ERROR: seat %"PRIu8" ran out of time\n", seat + 1 );
return -1;
}
/* parse out the state */
c = readMatchState( line, game, &tempState );
if( c < 0 ) {
/* couldn't get an intelligible state */
fprintf( stderr, "WARNING: bad state format in response\n" );
continue;
}
/* ignore responses that don't match the current state */
if( !matchStatesEqual( game, state, &tempState ) ) {
fprintf( stderr, "WARNING: ignoring un-requested response\n" );
continue;
}
/* get the action */
if( line[ c++ ] != ':'
|| ( r = readAction( &line[ c ], game, action ) ) < 0 ) {
if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {
fprintf( stderr, "ERROR: bad action format in response\n" );
}
fprintf( stderr,
"WARNING: bad action format in response, changed to call\n" );
action->type = a_call;
action->size = 0;
goto doneRead;
}
c += r;
/* make sure the action is valid */
if( !isValidAction( game, &state->state, 1, action ) ) {
if( checkErrorInvalidAction( seat, errorInfo ) < 0 ) {
fprintf( stderr, "ERROR: invalid action\n" );
return -1;
}
fprintf( stderr, "WARNING: invalid action, changed to call\n" );
action->type = a_call;
action->size = 0;
}
goto doneRead;
}
doneRead:
return 0;
}
/* returns >= 0 if match should continue, -1 for failure */
static int setUpNewHand( const Game *game, const uint8_t fixedSeats,
uint32_t *handId, uint8_t *player0Seat,
rng_state_t *rng, ErrorInfo *errorInfo, State *state )
{
++( *handId );
/* rotate the players around the table */
if( !fixedSeats ) {
*player0Seat = ( *player0Seat + 1 ) % game->numPlayers;
}
if( checkErrorNewHand( game, errorInfo ) < 0 ) {
fprintf( stderr, "ERROR: unexpected game\n" );
return -1;
}
initState( game, *handId, state );
dealCards( game, rng, state );
return 0;
}
/* returns >= 0 if match should continue, -1 for failure */
static int processTransactionFile( const Game *game, const int fixedSeats,
uint32_t *handId, uint8_t *player0Seat,
rng_state_t *rng, ErrorInfo *errorInfo,
double totalValue[ MAX_PLAYERS ],
MatchState *state, FILE *file )
{
int c, r;
uint32_t h;
uint8_t s;
Action action;
struct timeval sendTime, recvTime;
char line[ MAX_LINE_LEN ];
while( fgets( line, MAX_LINE_LEN, file ) ) {
/* get the log entry */
/* ACTION */
c = readAction( line, game, &action );
if( c < 0 ) {
fprintf( stderr, "ERROR: could not parse transaction action %s", line );
return -1;
}
/* ACTION HANDID SEND RECV */
if( sscanf( &line[ c ], " %"SCNu32" %zu.%06zu %zu.%06zu%n", &h,
&sendTime.tv_sec, &sendTime.tv_usec,
&recvTime.tv_sec, &recvTime.tv_usec, &r ) < 4 ) {
fprintf( stderr, "ERROR: could not parse transaction stamp %s", line );
return -1;
}
c += r;
/* check that we're processing the expected handId */
if( h != *handId ) {
fprintf( stderr, "ERROR: handId mismatch in transaction log: %s", line );
return -1;
}
/* make sure the action is valid */
if( !isValidAction( game, &state->state, 0, &action ) ) {
fprintf( stderr, "ERROR: invalid action in transaction log: %s", line );
return -1;
}
/* check for any timeout issues */
s = playerToSeat( game, *player0Seat,
currentPlayer( game, &state->state ) );
if( checkErrorTimes( s, &sendTime, &recvTime, errorInfo ) < 0 ) {
fprintf( stderr,
"ERROR: seat %"PRIu8" ran out of time in transaction file\n",
s + 1 );
return -1;
}
doAction( game, &action, &state->state );
if( stateFinished( &state->state ) ) {
/* hand is finished */
/* update the total value for each player */
for( s = 0; s < game->numPlayers; ++s ) {
totalValue[ s ]
+= valueOfState( game, &state->state,
seatToPlayer( game, *player0Seat, s ) );
}
/* move on to next hand */
if( setUpNewHand( game, fixedSeats, handId, player0Seat,
rng, errorInfo, &state->state ) < 0 ) {
return -1;
}
}
}
return 0;
}
/* returns >= 0 if match should continue, -1 on failure */
static int logTransaction( const Game *game, const State *state,
const Action *action,
const struct timeval *sendTime,
const struct timeval *recvTime,
FILE *file )
{
int c, r;
char line[ MAX_LINE_LEN ];
c = printAction( game, action, MAX_LINE_LEN, line );
if( c < 0 ) {
fprintf( stderr, "ERROR: transaction message too long\n" );
return -1;
}
r = snprintf( &line[ c ], MAX_LINE_LEN - c,
" %"PRIu32" %zu.%06zu %zu.%06zu\n",
state->handId, sendTime->tv_sec, sendTime->tv_usec,
recvTime->tv_sec, recvTime->tv_usec );
if( r < 0 ) {
fprintf( stderr, "ERROR: transaction message too long\n" );
return -1;
}
c += r;
if( fwrite( line, 1, c, file ) != c ) {
fprintf( stderr, "ERROR: could not write to transaction file\n" );
return -1;
}
fflush( file );
return c;
}
/* returns >= 0 if match should continue, -1 on failure */
static int checkVersion( const uint8_t seat,
ReadBuf *readBuf )
{
uint32_t major, minor, rev;
char line[ MAX_LINE_LEN ];
if( getLine( readBuf, MAX_LINE_LEN, line, -1 ) <= 0 ) {
fprintf( stderr,
"ERROR: could not read version string from seat %"PRIu8"\n",
seat + 1 );
return -1;
}
if( sscanf( line, "VERSION:%"SCNu32".%"SCNu32".%"SCNu32,
&major, &minor, &rev ) < 3 ) {
fprintf( stderr,
"ERROR: invalid version string %s", line );
return -1;
}
if( major != VERSION_MAJOR || minor > VERSION_MINOR ) {
fprintf( stderr, "ERROR: this server is currently using version %"SCNu32".%"SCNu32".%"SCNu32"\n", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION );
}
return 0;
}
/* returns >= 0 if match should continue, -1 on failure */
static int addToLogFile( const Game *game, const State *state,
const double value[ MAX_PLAYERS ],
const uint8_t player0Seat,
char *seatName[ MAX_PLAYERS ], FILE *logFile )
{
int c, r;
uint8_t p;
char line[ MAX_LINE_LEN ];
/* prepare the message */
c = printState( game, state, MAX_LINE_LEN, line );
if( c < 0 ) {
/* message is too long */
fprintf( stderr, "ERROR: log state message too long\n" );
return -1;
}
/* add the values */
for( p = 0; p < game->numPlayers; ++p ) {
r = snprintf( &line[ c ], MAX_LINE_LEN - c,
p ? "|%.6f" : ":%.6f", value[ p ] );
if( r < 0 ) {
fprintf( stderr, "ERROR: log message too long\n" );
return -1;
}
c += r;
/* remove trailing zeros after decimal-point */
while( line[ c - 1 ] == '0' ) { --c; }
if( line[ c - 1 ] == '.' ) { --c; }
line[ c ] = 0;
}
/* add the player names */
for( p = 0; p < game->numPlayers; ++p ) {
r = snprintf( &line[ c ], MAX_LINE_LEN - c,
p ? "|%s" : ":%s",
seatName[ playerToSeat( game, player0Seat, p ) ] );
if( r < 0 ) {
fprintf( stderr, "ERROR: log message too long\n" );
return -1;
}
c += r;
}
/* print the line to log and flush */
if( fprintf( logFile, "%s\n", line ) < 0 ) {
fprintf( stderr, "ERROR: logging failed for game %s\n", line );
return -1;
}
fflush( logFile );
return 0;
}
/* returns >= 0 if match should continue, -1 on failure */
static int printInitialMessage( const char *matchName, const char *gameName,
const uint32_t numHands, const uint32_t seed,
const ErrorInfo *info, FILE *logFile )
{
int c;
char line[ MAX_LINE_LEN ];
c = snprintf( line, MAX_LINE_LEN, "# name/game/hands/seed %s %s %"PRIu32" %"PRIu32"\n#--t_response %"PRIu64"\n#--t_hand %"PRIu64"\n#--t_per_hand %"PRIu64"\n",
matchName, gameName, numHands, seed,
info->maxResponseMicros / 1000,
info->maxUsedHandMicros / 1000,
info->maxUsedMatchMicros / numHands / 1000 );
if( c < 0 ) {
/* message is too long */
fprintf( stderr, "ERROR: initial game comment too long\n" );
return -1;
}
fprintf( stderr, "%s", line );
if( logFile ) {
fprintf( logFile, "%s", line );
}
return 0;
}
/* returns >= 0 if match should continue, -1 on failure */
static int printFinalMessage( const Game *game, char *seatName[ MAX_PLAYERS ],
const double totalValue[ MAX_PLAYERS ],
FILE *logFile )
{
int c, r;
uint8_t s;
char line[ MAX_LINE_LEN ];
c = snprintf( line, MAX_LINE_LEN, "SCORE" );
if( c < 0 ) {
/* message is too long */
fprintf( stderr, "ERROR: value state message too long\n" );
return -1;
}
for( s = 0; s < game->numPlayers; ++s ) {
r = snprintf( &line[ c ], MAX_LINE_LEN - c,
s ? "|%.6f" : ":%.6f", totalValue[ s ] );
if( r < 0 ) {
fprintf( stderr, "ERROR: value message too long\n" );
return -1;
}
c += r;
/* remove trailing zeros after decimal-point */
while( line[ c - 1 ] == '0' ) { --c; }
if( line[ c - 1 ] == '.' ) { --c; }
line[ c ] = 0;
}
/* add the player names */
for( s = 0; s < game->numPlayers; ++s ) {
r = snprintf( &line[ c ], MAX_LINE_LEN - c,
s ? "|%s" : ":%s", seatName[ s ] );
if( r < 0 ) {
fprintf( stderr, "ERROR: log message too long\n" );
return -1;
}
c += r;
}
fprintf( stdout, "%s\n", line );
fprintf( stderr, "%s\n", line );
if( logFile ) {
fprintf( logFile, "%s\n", line );
}
return 0;
}
/* run a match of numHands hands of the supplied game
cards are dealt using rng, error conditions like timeouts
are controlled and stored in errorInfo
actions are read/sent to seat p on seatFD[ p ]
if quiet is not zero, only print out errors, warnings, and final value
if logFile is not NULL, print out a single line for each completed
match with the final state and all player values. The values are
printed in player, not seat order.
if transactionFile is not NULL, a transaction log of actions made
is written to the file, and if there is any input left to read on
the stream when gameLoop is called, it will be processed to
initialise the state
returns >=0 if the match finished correctly, -1 on error */
static int gameLoop( const Game *game, char *seatName[ MAX_PLAYERS ],
const uint32_t numHands, const int quiet,
const int fixedSeats, rng_state_t *rng,
ErrorInfo *errorInfo, const int seatFD[ MAX_PLAYERS ],
ReadBuf *readBuf[ MAX_PLAYERS ],
FILE *logFile, FILE *transactionFile )
{
uint32_t handId;
uint8_t seat, p, player0Seat, currentP, currentSeat;
struct timeval t, sendTime, recvTime;
Action action;
MatchState state;
double value[ MAX_PLAYERS ], totalValue[ MAX_PLAYERS ];
/* check version string for each player */
for( seat = 0; seat < game->numPlayers; ++seat ) {
if( checkVersion( seat, readBuf[ seat ] ) < 0 ) {
/* error messages already handled in function */
return -1;
}
}
gettimeofday( &sendTime, NULL );
if( !quiet ) {
fprintf( stderr, "STARTED at %zu.%06zu\n",
sendTime.tv_sec, sendTime.tv_usec );
}
/* start at the first hand */
handId = 0;
if( checkErrorNewHand( game, errorInfo ) < 0 ) {
fprintf( stderr, "ERROR: unexpected game\n" );
return -1;
}
initState( game, handId, &state.state );
dealCards( game, rng, &state.state );
for( seat = 0; seat < game->numPlayers; ++seat ) {
totalValue[ seat ] = 0.0;
}
/* seat 0 is player 0 in first game */
player0Seat = 0;
/* process the transaction file */
if( transactionFile != NULL ) {
if( processTransactionFile( game, fixedSeats, &handId, &player0Seat,
rng, errorInfo, totalValue,
&state, transactionFile ) < 0 ) {
/* error messages already handled in function */
return -1;
}
}
if( handId >= numHands ) {
goto finishedGameLoop;
}
/* play all the (remaining) hands */
while( 1 ) {
/* play the hand */
while( !stateFinished( &state.state ) ) {
/* find the current player */
currentP = currentPlayer( game, &state.state );
/* send state to each player */
for( seat = 0; seat < game->numPlayers; ++seat ) {
state.viewingPlayer = seatToPlayer( game, player0Seat, seat );
if( sendPlayerMessage( game, &state, quiet, seat,
seatFD[ seat ], &t ) < 0 ) {
/* error messages already handled in function */
return -1;
}
/* remember the seat and send time if player is acting */
if( state.viewingPlayer == currentP ) {
sendTime = t;
}
}
/* get action from current player */
state.viewingPlayer = currentP;
currentSeat = playerToSeat( game, player0Seat, currentP );
if( readPlayerResponse( game, &state, quiet, currentSeat, &sendTime,
errorInfo, readBuf[ currentSeat ],
&action, &recvTime ) < 0 ) {
/* error messages already handled in function */
return -1;
}
/* log the transaction */
if( transactionFile != NULL ) {
if( logTransaction( game, &state.state, &action,
&sendTime, &recvTime, transactionFile ) < 0 ) {
/* error messages already handled in function */
return -1;
}
}
/* do the action */
doAction( game, &action, &state.state );
}
/* get values */
for( p = 0; p < game->numPlayers; ++p ) {
value[ p ] = valueOfState( game, &state.state, p );
totalValue[ playerToSeat( game, player0Seat, p ) ] += value[ p ];
}
/* add the game to the log */
if( logFile != NULL ) {
if( addToLogFile( game, &state.state, value, player0Seat,
seatName, logFile ) < 0 ) {
/* error messages already handled in function */
return -1;
}
}
/* send final state to each player */
for( seat = 0; seat < game->numPlayers; ++seat ) {
state.viewingPlayer = seatToPlayer( game, player0Seat, seat );
if( sendPlayerMessage( game, &state, quiet, seat,
seatFD[ seat ], &t ) < 0 ) {
/* error messages already handled in function */
return -1;
}
}
if ( !quiet ) {
if ( handId % 100 == 0) {
for( seat = 0; seat < game->numPlayers; ++seat ) {
fprintf(stderr, "Seconds cumulatively spent in match for seat %i: "
"%i\n", seat,
(int)(errorInfo->usedMatchMicros[ seat ] / 1000000));
}
}
}
/* start a new hand */
if( setUpNewHand( game, fixedSeats, &handId, &player0Seat,
rng, errorInfo, &state.state ) < 0 ) {
/* error messages already handled in function */
return -1;
}
if( handId >= numHands ) {
break;
}
}
finishedGameLoop:
/* print out the final values */
if( !quiet ) {
gettimeofday( &t, NULL );
fprintf( stderr, "FINISHED at %zu.%06zu\n",
sendTime.tv_sec, sendTime.tv_usec );
}
if( printFinalMessage( game, seatName, totalValue, logFile ) < 0 ) {
/* error messages already handled in function */
return -1;
}
return 0;
}
int main( int argc, char **argv )
{
int i, listenSocket[ MAX_PLAYERS ], v, longOpt;
int fixedSeats, quiet, append;
int seatFD[ MAX_PLAYERS ];
FILE *file, *logFile, *transactionFile;
ReadBuf *readBuf[ MAX_PLAYERS ];
Game *game;
rng_state_t rng;
ErrorInfo errorInfo;
struct sockaddr_in addr;
socklen_t addrLen;
char *seatName[ MAX_PLAYERS ];
int useLogFile, useTransactionFile;
uint64_t maxResponseMicros, maxUsedHandMicros, maxUsedPerHandMicros;
int64_t startTimeoutMicros;
uint32_t numHands, seed, maxInvalidActions;
uint16_t listenPort[ MAX_PLAYERS ];
struct timeval startTime, tv;
char name[ MAX_LINE_LEN ];
static struct option longOptions[] = {
{ "t_response", 1, 0, 0 },
{ "t_hand", 1, 0, 0 },
{ "t_per_hand", 1, 0, 0 },
{ "start_timeout", 1, 0, 0 },
{ 0, 0, 0, 0 }
};
/* set defaults */
/* game error conditions */
maxInvalidActions = DEFAULT_MAX_INVALID_ACTIONS;
maxResponseMicros = DEFAULT_MAX_RESPONSE_MICROS;
maxUsedHandMicros = DEFAULT_MAX_USED_HAND_MICROS;
maxUsedPerHandMicros = DEFAULT_MAX_USED_PER_HAND_MICROS;
/* use random ports */
for( i = 0; i < MAX_PLAYERS; ++i ) {
listenPort[ i ] = 0;
}
/* use log file, don't use transaction file */
useLogFile = 1;
useTransactionFile = 0;
/* print all messages */
quiet = 0;
/* by default, overwrite preexisting log/transaction files */
append = 0;
/* players rotate around the table */
fixedSeats = 0;
/* no timeout on startup */
startTimeoutMicros = -1;
/* parse options */
while( 1 ) {
i = getopt_long( argc, argv, "flLp:qtTa", longOptions, &longOpt );
if( i < 0 ) {
break;
}
switch( i ) {
case 0:
/* long option longOpt */
switch( longOpt ) {
case 0:
/* t_response */
if( sscanf( optarg, "%"SCNu64, &maxResponseMicros ) < 1 ) {
fprintf( stderr, "ERROR: could not get response timeout from %s\n",
optarg );
exit( EXIT_FAILURE );
}
/* convert from milliseconds to microseconds */
maxResponseMicros *= 1000;
break;
case 1:
/* t_hand */
if( sscanf( optarg, "%"SCNu64, &maxUsedHandMicros ) < 1 ) {
fprintf( stderr,
"ERROR: could not get player hand timeout from %s\n",
optarg );
exit( EXIT_FAILURE );
}
/* convert from milliseconds to microseconds */
maxUsedHandMicros *= 1000;
break;
case 2:
/* t_per_hand */
if( sscanf( optarg, "%"SCNu64, &maxUsedPerHandMicros ) < 1 ) {
fprintf( stderr, "ERROR: could not get average player hand timeout from %s\n", optarg );
exit( EXIT_FAILURE );
}
/* convert from milliseconds to microseconds */
maxUsedPerHandMicros *= 1000;
break;
case 3:
/* start_timeout */
if( sscanf( optarg, "%"SCNd64, &startTimeoutMicros ) < 1 ) {
fprintf( stderr, "ERROR: could not get start timeout %s\n", optarg );
exit( EXIT_FAILURE );
}
/* convert from milliseconds to microseconds */
if( startTimeoutMicros > 0 ) {
startTimeoutMicros *= 1000;
}
break;
}
break;
case 'f':
/* fix the player seats */;
fixedSeats = 1;
break;
case 'l':
/* no transactionFile */;
useLogFile = 0;
break;
case 'L':
/* use transactionFile */;
useLogFile = 1;
break;
case 'p':
/* port specification */
if( scanPortString( optarg, listenPort ) < 0 ) {
fprintf( stderr, "ERROR: bad port string %s\n", optarg );
exit( EXIT_FAILURE );
}
break;
case 'q':
quiet = 1;
break;
case 't':
/* no transactionFile */
useTransactionFile = 0;
break;
case 'T':
/* use transactionFile */
useTransactionFile = 1;
break;
case 'a':
append = 1;
break;
default:
fprintf( stderr, "ERROR: unknown option %c\n", i );
exit( EXIT_FAILURE );
}
}
if( optind + 4 > argc ) {
printUsage( stdout, 0 );
exit( EXIT_FAILURE );
}
/* get the game definition */
file = fopen( argv[ optind + 1 ], "r" );
if( file == NULL ) {
fprintf( stderr, "ERROR: could not open game definition %s\n",
argv[ optind + 1 ] );
exit( EXIT_FAILURE );
}
game = readGame( file );
if( game == NULL ) {
fprintf( stderr, "ERROR: could not read game %s\n", argv[ optind + 1 ] );
exit( EXIT_FAILURE );
}
fclose( file );
/* save the seat names */
if( optind + 4 + game->numPlayers > argc ) {
printUsage( stdout, 0 );
exit( EXIT_FAILURE );
}
for( i = 0; i < game->numPlayers; ++i ) {
seatName[ i ] = argv[ optind + 4 + i ];
}
/* get number of hands */
if( sscanf( argv[ optind + 2 ], "%"SCNu32, &numHands ) < 1
|| numHands == 0 ) {
fprintf( stderr, "ERROR: invalid number of hands %s\n",
argv[ optind + 2 ] );
exit( EXIT_FAILURE );
}
/* get random number seed */
if( sscanf( argv[ optind + 3 ], "%"SCNu32, &seed ) < 1 ) {
fprintf( stderr, "ERROR: invalid random number seed %s\n",
argv[ optind + 3 ] );
exit( EXIT_FAILURE );
}
init_genrand( &rng, seed );
srandom( seed ); /* used for random port selection */
if( useLogFile ) {
/* create/open the log */
if( snprintf( name, MAX_LINE_LEN, "%s.log", argv[ optind ] ) < 0 ) {
fprintf( stderr, "ERROR: match file name too long %s\n", argv[ optind ] );
exit( EXIT_FAILURE );
}
if (append) {
logFile = fopen( name, "a+" );
} else {
logFile = fopen( name, "w" );
}
if( logFile == NULL ) {
fprintf( stderr, "ERROR: could not open log file %s\n", name );
exit( EXIT_FAILURE );
}
} else {
/* no log file */
logFile = NULL;
}
if( useTransactionFile ) {
/* create/open the transaction log */
if( snprintf( name, MAX_LINE_LEN, "%s.tlog", argv[ optind ] ) < 0 ) {
fprintf( stderr, "ERROR: match file name too long %s\n", argv[ optind ] );
exit( EXIT_FAILURE );
}
if (append) {
transactionFile = fopen( name, "a+" );
} else {
transactionFile = fopen( name, "w" );
}
if( transactionFile == NULL ) {
fprintf( stderr, "ERROR: could not open transaction file %s\n", name );
exit( EXIT_FAILURE );
}
} else {
/* no transaction file */
transactionFile = NULL;
}
/* set up the error info */
initErrorInfo( maxInvalidActions, maxResponseMicros, maxUsedHandMicros,
maxUsedPerHandMicros * numHands, &errorInfo );
/* open sockets for players to connect to */
for( i = 0; i < game->numPlayers; ++i ) {
listenSocket[ i ] = getListenSocket( &listenPort[ i ] );
if( listenSocket[ i ] < 0 ) {
fprintf( stderr, "ERROR: could not create listen socket for player %d\n",
i + 1 );
exit( EXIT_FAILURE );
}
}
/* print out the final port assignments */
for( i = 0; i < game->numPlayers; ++i ) {
printf( i ? " %"PRIu16 : "%"PRIu16, listenPort[ i ] );
}
printf( "\n" );
fflush( stdout );
/* print out usage information */
printInitialMessage( argv[ optind ], argv[ optind + 1 ],
numHands, seed, &errorInfo, logFile );
/* wait for each player to connect */
gettimeofday( &startTime, NULL );
for( i = 0; i < game->numPlayers; ++i ) {
if( startTimeoutMicros >= 0 ) {
uint64_t startTimeLeft;
fd_set fds;
gettimeofday( &tv, NULL );
startTimeLeft = startTimeoutMicros
- (uint64_t)( tv.tv_sec - startTime.tv_sec ) * 1000000
- ( tv.tv_usec - startTime.tv_usec );
if( startTimeLeft < 0 ) {
startTimeLeft = 0;
}
tv.tv_sec = startTimeLeft / 1000000;
tv.tv_usec = startTimeLeft % 1000000;
FD_ZERO( &fds );
FD_SET( listenSocket[ i ], &fds );
if( select( listenSocket[ i ] + 1, &fds, NULL, NULL, &tv ) < 1 ) {
/* no input ready within time, or an actual error */
fprintf( stderr, "ERROR: timed out waiting for seat %d to connect\n",
i + 1 );
exit( EXIT_FAILURE );
}
}
addrLen = sizeof( addr );
seatFD[ i ] = accept( listenSocket[ i ],
(struct sockaddr *)&addr, &addrLen );
if( seatFD[ i ] < 0 ) {
fprintf( stderr, "ERROR: seat %d could not connect\n", i + 1 );
exit( EXIT_FAILURE );
}
close( listenSocket[ i ] );
v = 1;
setsockopt( seatFD[ i ], IPPROTO_TCP, TCP_NODELAY,
(char *)&v, sizeof(int) );
readBuf[ i ] = createReadBuf( seatFD[ i ] );
}
/* play the match */
if( gameLoop( game, seatName, numHands, quiet, fixedSeats, &rng, &errorInfo,
seatFD, readBuf, logFile, transactionFile ) < 0 ) {
/* should have already printed an error message */
exit( EXIT_FAILURE );
}
fflush( stderr );
fflush( stdout );
if( transactionFile != NULL ) {
fclose( transactionFile );
}
if( logFile != NULL ) {
fclose( logFile );
}
free( game );
return EXIT_SUCCESS;
}
================================================
FILE: ACPCServer/evalHandTables
================================================
/*
Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta
*/
/* high card 1287 0
pair 3718 1287
two pair 3601 5005
trips 1014 8606
straight 13 9620
flush 1287 9633
f_house 1014 10920
quads 169 11934
s_flush 13 12103 */
#define HANDCLASS_SINGLE_CARD 0
#define HANDCLASS_PAIR 1287
#define HANDCLASS_TWO_PAIR 5005
#define HANDCLASS_TRIPS 8606
#define HANDCLASS_STRAIGHT 9620
#define HANDCLASS_FLUSH 9633
#define HANDCLASS_FULL_HOUSE 10920
#define HANDCLASS_QUADS 11934
#define HANDCLASS_STRAIGHT_FLUSH 12103
typedef union {
uint16_t bySuit[ 4 ];
uint64_t cards;
} Cardset;
static const uint16_t oneSuitVal[ 8192 ] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 12107,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9634,
0, 0, 0, 0, 0, 0, 0, 9635,
0, 0, 0, 9636, 0, 9637, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9639,
0, 0, 0, 0, 0, 0, 0, 9640,
0, 0, 0, 9641, 0, 9642, 9643, 12107,
0, 0, 0, 0, 0, 0, 0, 9644,
0, 0, 0, 9645, 0, 9646, 9647, 9647,
0, 0, 0, 9648, 0, 9649, 9650, 9650,
0, 9651, 9652, 9652, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9654,
0, 0, 0, 0, 0, 0, 0, 9655,
0, 0, 0, 9656, 0, 9657, 9658, 12107,
0, 0, 0, 0, 0, 0, 0, 9659,
0, 0, 0, 9660, 0, 9661, 9662, 9662,
0, 0, 0, 9663, 0, 9664, 9665, 9665,
0, 9666, 9667, 9667, 9668, 9668, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 9669,
0, 0, 0, 9670, 0, 9671, 9672, 9672,
0, 0, 0, 9673, 0, 9674, 9675, 9675,
0, 9676, 9677, 9677, 9678, 9678, 9678, 12107,
0, 0, 0, 9679, 0, 9680, 9681, 9681,
0, 9682, 9683, 9683, 9684, 9684, 9684, 9684,
0, 9685, 9686, 9686, 9687, 9687, 9687, 9687,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9689,
0, 0, 0, 0, 0, 0, 0, 9690,
0, 0, 0, 9691, 0, 9692, 9693, 12107,
0, 0, 0, 0, 0, 0, 0, 9694,
0, 0, 0, 9695, 0, 9696, 9697, 9697,
0, 0, 0, 9698, 0, 9699, 9700, 9700,
0, 9701, 9702, 9702, 9703, 9703, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 9704,
0, 0, 0, 9705, 0, 9706, 9707, 9707,
0, 0, 0, 9708, 0, 9709, 9710, 9710,
0, 9711, 9712, 9712, 9713, 9713, 9713, 12107,
0, 0, 0, 9714, 0, 9715, 9716, 9716,
0, 9717, 9718, 9718, 9719, 9719, 9719, 9719,
0, 9720, 9721, 9721, 9722, 9722, 9722, 9722,
9723, 9723, 9723, 9723, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 9724,
0, 0, 0, 9725, 0, 9726, 9727, 9727,
0, 0, 0, 9728, 0, 9729, 9730, 9730,
0, 9731, 9732, 9732, 9733, 9733, 9733, 12107,
0, 0, 0, 9734, 0, 9735, 9736, 9736,
0, 9737, 9738, 9738, 9739, 9739, 9739, 9739,
0, 9740, 9741, 9741, 9742, 9742, 9742, 9742,
9743, 9743, 9743, 9743, 9743, 9743, 12108, 12108,
0, 0, 0, 9744, 0, 9745, 9746, 9746,
0, 9747, 9748, 9748, 9749, 9749, 9749, 9749,
0, 9750, 9751, 9751, 9752, 9752, 9752, 9752,
9753, 9753, 9753, 9753, 9753, 9753, 9753, 12107,
0, 9754, 9755, 9755, 9756, 9756, 9756, 9756,
9757, 9757, 9757, 9757, 9757, 9757, 9757, 9757,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9759,
0, 0, 0, 0, 0, 0, 0, 9760,
0, 0, 0, 9761, 0, 9762, 9763, 12107,
0, 0, 0, 0, 0, 0, 0, 9764,
0, 0, 0, 9765, 0, 9766, 9767, 9767,
0, 0, 0, 9768, 0, 9769, 9770, 9770,
0, 9771, 9772, 9772, 9773, 9773, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 9774,
0, 0, 0, 9775, 0, 9776, 9777, 9777,
0, 0, 0, 9778, 0, 9779, 9780, 9780,
0, 9781, 9782, 9782, 9783, 9783, 9783, 12107,
0, 0, 0, 9784, 0, 9785, 9786, 9786,
0, 9787, 9788, 9788, 9789, 9789, 9789, 9789,
0, 9790, 9791, 9791, 9792, 9792, 9792, 9792,
9793, 9793, 9793, 9793, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 9794,
0, 0, 0, 9795, 0, 9796, 9797, 9797,
0, 0, 0, 9798, 0, 9799, 9800, 9800,
0, 9801, 9802, 9802, 9803, 9803, 9803, 12107,
0, 0, 0, 9804, 0, 9805, 9806, 9806,
0, 9807, 9808, 9808, 9809, 9809, 9809, 9809,
0, 9810, 9811, 9811, 9812, 9812, 9812, 9812,
9813, 9813, 9813, 9813, 9813, 9813, 12108, 12108,
0, 0, 0, 9814, 0, 9815, 9816, 9816,
0, 9817, 9818, 9818, 9819, 9819, 9819, 9819,
0, 9820, 9821, 9821, 9822, 9822, 9822, 9822,
9823, 9823, 9823, 9823, 9823, 9823, 9823, 12107,
0, 9824, 9825, 9825, 9826, 9826, 9826, 9826,
9827, 9827, 9827, 9827, 9827, 9827, 9827, 9827,
9828, 9828, 9828, 9828, 9828, 9828, 9828, 9828,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 0, 0, 0, 0, 9829,
0, 0, 0, 9830, 0, 9831, 9832, 9832,
0, 0, 0, 9833, 0, 9834, 9835, 9835,
0, 9836, 9837, 9837, 9838, 9838, 9838, 12107,
0, 0, 0, 9839, 0, 9840, 9841, 9841,
0, 9842, 9843, 9843, 9844, 9844, 9844, 9844,
0, 9845, 9846, 9846, 9847, 9847, 9847, 9847,
9848, 9848, 9848, 9848, 9848, 9848, 12108, 12108,
0, 0, 0, 9849, 0, 9850, 9851, 9851,
0, 9852, 9853, 9853, 9854, 9854, 9854, 9854,
0, 9855, 9856, 9856, 9857, 9857, 9857, 9857,
9858, 9858, 9858, 9858, 9858, 9858, 9858, 12107,
0, 9859, 9860, 9860, 9861, 9861, 9861, 9861,
9862, 9862, 9862, 9862, 9862, 9862, 9862, 9862,
9863, 9863, 9863, 9863, 9863, 9863, 9863, 9863,
9863, 9863, 9863, 9863, 12109, 12109, 12109, 12109,
0, 0, 0, 9864, 0, 9865, 9866, 9866,
0, 9867, 9868, 9868, 9869, 9869, 9869, 9869,
0, 9870, 9871, 9871, 9872, 9872, 9872, 9872,
9873, 9873, 9873, 9873, 9873, 9873, 9873, 12107,
0, 9874, 9875, 9875, 9876, 9876, 9876, 9876,
9877, 9877, 9877, 9877, 9877, 9877, 9877, 9877,
9878, 9878, 9878, 9878, 9878, 9878, 9878, 9878,
9878, 9878, 9878, 9878, 9878, 9878, 12108, 12108,
0, 9879, 9880, 9880, 9881, 9881, 9881, 9881,
9882, 9882, 9882, 9882, 9882, 9882, 9882, 9882,
9883, 9883, 9883, 9883, 9883, 9883, 9883, 9883,
9883, 9883, 9883, 9883, 9883, 9883, 9883, 12107,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 9885,
0, 0, 0, 0, 0, 0, 0, 9886,
0, 0, 0, 9887, 0, 9888, 9889, 12107,
0, 0, 0, 0, 0, 0, 0, 9890,
0, 0, 0, 9891, 0, 9892, 9893, 9893,
0, 0, 0, 9894, 0, 9895, 9896, 9896,
0, 9897, 9898, 9898, 9899, 9899, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 9900,
0, 0, 0, 9901, 0, 9902, 9903, 9903,
0, 0, 0, 9904, 0, 9905, 9906, 9906,
0, 9907, 9908, 9908, 9909, 9909, 9909, 12107,
0, 0, 0, 9910, 0, 9911, 9912, 9912,
0, 9913, 9914, 9914, 9915, 9915, 9915, 9915,
0, 9916, 9917, 9917, 9918, 9918, 9918, 9918,
9919, 9919, 9919, 9919, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 9920,
0, 0, 0, 9921, 0, 9922, 9923, 9923,
0, 0, 0, 9924, 0, 9925, 9926, 9926,
0, 9927, 9928, 9928, 9929, 9929, 9929, 12107,
0, 0, 0, 9930, 0, 9931, 9932, 9932,
0, 9933, 9934, 9934, 9935, 9935, 9935, 9935,
0, 9936, 9937, 9937, 9938, 9938, 9938, 9938,
9939, 9939, 9939, 9939, 9939, 9939, 12108, 12108,
0, 0, 0, 9940, 0, 9941, 9942, 9942,
0, 9943, 9944, 9944, 9945, 9945, 9945, 9945,
0, 9946, 9947, 9947, 9948, 9948, 9948, 9948,
9949, 9949, 9949, 9949, 9949, 9949, 9949, 12107,
0, 9950, 9951, 9951, 9952, 9952, 9952, 9952,
9953, 9953, 9953, 9953, 9953, 9953, 9953, 9953,
9954, 9954, 9954, 9954, 9954, 9954, 9954, 9954,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 0, 0, 0, 0, 9955,
0, 0, 0, 9956, 0, 9957, 9958, 9958,
0, 0, 0, 9959, 0, 9960, 9961, 9961,
0, 9962, 9963, 9963, 9964, 9964, 9964, 12107,
0, 0, 0, 9965, 0, 9966, 9967, 9967,
0, 9968, 9969, 9969, 9970, 9970, 9970, 9970,
0, 9971, 9972, 9972, 9973, 9973, 9973, 9973,
9974, 9974, 9974, 9974, 9974, 9974, 12108, 12108,
0, 0, 0, 9975, 0, 9976, 9977, 9977,
0, 9978, 9979, 9979, 9980, 9980, 9980, 9980,
0, 9981, 9982, 9982, 9983, 9983, 9983, 9983,
9984, 9984, 9984, 9984, 9984, 9984, 9984, 12107,
0, 9985, 9986, 9986, 9987, 9987, 9987, 9987,
9988, 9988, 9988, 9988, 9988, 9988, 9988, 9988,
9989, 9989, 9989, 9989, 9989, 9989, 9989, 9989,
9989, 9989, 9989, 9989, 12109, 12109, 12109, 12109,
0, 0, 0, 9990, 0, 9991, 9992, 9992,
0, 9993, 9994, 9994, 9995, 9995, 9995, 9995,
0, 9996, 9997, 9997, 9998, 9998, 9998, 9998,
9999, 9999, 9999, 9999, 9999, 9999, 9999, 12107,
0, 10000, 10001, 10001, 10002, 10002, 10002, 10002,
10003, 10003, 10003, 10003, 10003, 10003, 10003, 10003,
10004, 10004, 10004, 10004, 10004, 10004, 10004, 10004,
10004, 10004, 10004, 10004, 10004, 10004, 12108, 12108,
0, 10005, 10006, 10006, 10007, 10007, 10007, 10007,
10008, 10008, 10008, 10008, 10008, 10008, 10008, 10008,
10009, 10009, 10009, 10009, 10009, 10009, 10009, 10009,
10009, 10009, 10009, 10009, 10009, 10009, 10009, 12107,
10010, 10010, 10010, 10010, 10010, 10010, 10010, 10010,
10010, 10010, 10010, 10010, 10010, 10010, 10010, 10010,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 0, 0, 0, 0, 10011,
0, 0, 0, 10012, 0, 10013, 10014, 10014,
0, 0, 0, 10015, 0, 10016, 10017, 10017,
0, 10018, 10019, 10019, 10020, 10020, 10020, 12107,
0, 0, 0, 10021, 0, 10022, 10023, 10023,
0, 10024, 10025, 10025, 10026, 10026, 10026, 10026,
0, 10027, 10028, 10028, 10029, 10029, 10029, 10029,
10030, 10030, 10030, 10030, 10030, 10030, 12108, 12108,
0, 0, 0, 10031, 0, 10032, 10033, 10033,
0, 10034, 10035, 10035, 10036, 10036, 10036, 10036,
0, 10037, 10038, 10038, 10039, 10039, 10039, 10039,
10040, 10040, 10040, 10040, 10040, 10040, 10040, 12107,
0, 10041, 10042, 10042, 10043, 10043, 10043, 10043,
10044, 10044, 10044, 10044, 10044, 10044, 10044, 10044,
10045, 10045, 10045, 10045, 10045, 10045, 10045, 10045,
10045, 10045, 10045, 10045, 12109, 12109, 12109, 12109,
0, 0, 0, 10046, 0, 10047, 10048, 10048,
0, 10049, 10050, 10050, 10051, 10051, 10051, 10051,
0, 10052, 10053, 10053, 10054, 10054, 10054, 10054,
10055, 10055, 10055, 10055, 10055, 10055, 10055, 12107,
0, 10056, 10057, 10057, 10058, 10058, 10058, 10058,
10059, 10059, 10059, 10059, 10059, 10059, 10059, 10059,
10060, 10060, 10060, 10060, 10060, 10060, 10060, 10060,
10060, 10060, 10060, 10060, 10060, 10060, 12108, 12108,
0, 10061, 10062, 10062, 10063, 10063, 10063, 10063,
10064, 10064, 10064, 10064, 10064, 10064, 10064, 10064,
10065, 10065, 10065, 10065, 10065, 10065, 10065, 10065,
10065, 10065, 10065, 10065, 10065, 10065, 10065, 12107,
10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066,
10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066,
10066, 10066, 10066, 10066, 10066, 10066, 10066, 10066,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10067, 0, 10068, 10069, 10069,
0, 10070, 10071, 10071, 10072, 10072, 10072, 10072,
0, 10073, 10074, 10074, 10075, 10075, 10075, 10075,
10076, 10076, 10076, 10076, 10076, 10076, 10076, 12107,
0, 10077, 10078, 10078, 10079, 10079, 10079, 10079,
10080, 10080, 10080, 10080, 10080, 10080, 10080, 10080,
10081, 10081, 10081, 10081, 10081, 10081, 10081, 10081,
10081, 10081, 10081, 10081, 10081, 10081, 12108, 12108,
0, 10082, 10083, 10083, 10084, 10084, 10084, 10084,
10085, 10085, 10085, 10085, 10085, 10085, 10085, 10085,
10086, 10086, 10086, 10086, 10086, 10086, 10086, 10086,
10086, 10086, 10086, 10086, 10086, 10086, 10086, 12107,
10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087,
10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087,
10087, 10087, 10087, 10087, 10087, 10087, 10087, 10087,
10087, 10087, 10087, 10087, 12109, 12109, 12109, 12109,
0, 10088, 10089, 10089, 10090, 10090, 10090, 10090,
10091, 10091, 10091, 10091, 10091, 10091, 10091, 10091,
10092, 10092, 10092, 10092, 10092, 10092, 10092, 10092,
10092, 10092, 10092, 10092, 10092, 10092, 10092, 12107,
10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093,
10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093,
10093, 10093, 10093, 10093, 10093, 10093, 10093, 10093,
10093, 10093, 10093, 10093, 10093, 10093, 12108, 12108,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 10095,
0, 0, 0, 0, 0, 0, 0, 10096,
0, 0, 0, 10097, 0, 10098, 10099, 12107,
0, 0, 0, 0, 0, 0, 0, 10100,
0, 0, 0, 10101, 0, 10102, 10103, 10103,
0, 0, 0, 10104, 0, 10105, 10106, 10106,
0, 10107, 10108, 10108, 10109, 10109, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 10110,
0, 0, 0, 10111, 0, 10112, 10113, 10113,
0, 0, 0, 10114, 0, 10115, 10116, 10116,
0, 10117, 10118, 10118, 10119, 10119, 10119, 12107,
0, 0, 0, 10120, 0, 10121, 10122, 10122,
0, 10123, 10124, 10124, 10125, 10125, 10125, 10125,
0, 10126, 10127, 10127, 10128, 10128, 10128, 10128,
10129, 10129, 10129, 10129, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 10130,
0, 0, 0, 10131, 0, 10132, 10133, 10133,
0, 0, 0, 10134, 0, 10135, 10136, 10136,
0, 10137, 10138, 10138, 10139, 10139, 10139, 12107,
0, 0, 0, 10140, 0, 10141, 10142, 10142,
0, 10143, 10144, 10144, 10145, 10145, 10145, 10145,
0, 10146, 10147, 10147, 10148, 10148, 10148, 10148,
10149, 10149, 10149, 10149, 10149, 10149, 12108, 12108,
0, 0, 0, 10150, 0, 10151, 10152, 10152,
0, 10153, 10154, 10154, 10155, 10155, 10155, 10155,
0, 10156, 10157, 10157, 10158, 10158, 10158, 10158,
10159, 10159, 10159, 10159, 10159, 10159, 10159, 12107,
0, 10160, 10161, 10161, 10162, 10162, 10162, 10162,
10163, 10163, 10163, 10163, 10163, 10163, 10163, 10163,
10164, 10164, 10164, 10164, 10164, 10164, 10164, 10164,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 0, 0, 0, 0, 10165,
0, 0, 0, 10166, 0, 10167, 10168, 10168,
0, 0, 0, 10169, 0, 10170, 10171, 10171,
0, 10172, 10173, 10173, 10174, 10174, 10174, 12107,
0, 0, 0, 10175, 0, 10176, 10177, 10177,
0, 10178, 10179, 10179, 10180, 10180, 10180, 10180,
0, 10181, 10182, 10182, 10183, 10183, 10183, 10183,
10184, 10184, 10184, 10184, 10184, 10184, 12108, 12108,
0, 0, 0, 10185, 0, 10186, 10187, 10187,
0, 10188, 10189, 10189, 10190, 10190, 10190, 10190,
0, 10191, 10192, 10192, 10193, 10193, 10193, 10193,
10194, 10194, 10194, 10194, 10194, 10194, 10194, 12107,
0, 10195, 10196, 10196, 10197, 10197, 10197, 10197,
10198, 10198, 10198, 10198, 10198, 10198, 10198, 10198,
10199, 10199, 10199, 10199, 10199, 10199, 10199, 10199,
10199, 10199, 10199, 10199, 12109, 12109, 12109, 12109,
0, 0, 0, 10200, 0, 10201, 10202, 10202,
0, 10203, 10204, 10204, 10205, 10205, 10205, 10205,
0, 10206, 10207, 10207, 10208, 10208, 10208, 10208,
10209, 10209, 10209, 10209, 10209, 10209, 10209, 12107,
0, 10210, 10211, 10211, 10212, 10212, 10212, 10212,
10213, 10213, 10213, 10213, 10213, 10213, 10213, 10213,
10214, 10214, 10214, 10214, 10214, 10214, 10214, 10214,
10214, 10214, 10214, 10214, 10214, 10214, 12108, 12108,
0, 10215, 10216, 10216, 10217, 10217, 10217, 10217,
10218, 10218, 10218, 10218, 10218, 10218, 10218, 10218,
10219, 10219, 10219, 10219, 10219, 10219, 10219, 10219,
10219, 10219, 10219, 10219, 10219, 10219, 10219, 12107,
10220, 10220, 10220, 10220, 10220, 10220, 10220, 10220,
10220, 10220, 10220, 10220, 10220, 10220, 10220, 10220,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 0, 0, 0, 0, 10221,
0, 0, 0, 10222, 0, 10223, 10224, 10224,
0, 0, 0, 10225, 0, 10226, 10227, 10227,
0, 10228, 10229, 10229, 10230, 10230, 10230, 12107,
0, 0, 0, 10231, 0, 10232, 10233, 10233,
0, 10234, 10235, 10235, 10236, 10236, 10236, 10236,
0, 10237, 10238, 10238, 10239, 10239, 10239, 10239,
10240, 10240, 10240, 10240, 10240, 10240, 12108, 12108,
0, 0, 0, 10241, 0, 10242, 10243, 10243,
0, 10244, 10245, 10245, 10246, 10246, 10246, 10246,
0, 10247, 10248, 10248, 10249, 10249, 10249, 10249,
10250, 10250, 10250, 10250, 10250, 10250, 10250, 12107,
0, 10251, 10252, 10252, 10253, 10253, 10253, 10253,
10254, 10254, 10254, 10254, 10254, 10254, 10254, 10254,
10255, 10255, 10255, 10255, 10255, 10255, 10255, 10255,
10255, 10255, 10255, 10255, 12109, 12109, 12109, 12109,
0, 0, 0, 10256, 0, 10257, 10258, 10258,
0, 10259, 10260, 10260, 10261, 10261, 10261, 10261,
0, 10262, 10263, 10263, 10264, 10264, 10264, 10264,
10265, 10265, 10265, 10265, 10265, 10265, 10265, 12107,
0, 10266, 10267, 10267, 10268, 10268, 10268, 10268,
10269, 10269, 10269, 10269, 10269, 10269, 10269, 10269,
10270, 10270, 10270, 10270, 10270, 10270, 10270, 10270,
10270, 10270, 10270, 10270, 10270, 10270, 12108, 12108,
0, 10271, 10272, 10272, 10273, 10273, 10273, 10273,
10274, 10274, 10274, 10274, 10274, 10274, 10274, 10274,
10275, 10275, 10275, 10275, 10275, 10275, 10275, 10275,
10275, 10275, 10275, 10275, 10275, 10275, 10275, 12107,
10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276,
10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276,
10276, 10276, 10276, 10276, 10276, 10276, 10276, 10276,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10277, 0, 10278, 10279, 10279,
0, 10280, 10281, 10281, 10282, 10282, 10282, 10282,
0, 10283, 10284, 10284, 10285, 10285, 10285, 10285,
10286, 10286, 10286, 10286, 10286, 10286, 10286, 12107,
0, 10287, 10288, 10288, 10289, 10289, 10289, 10289,
10290, 10290, 10290, 10290, 10290, 10290, 10290, 10290,
10291, 10291, 10291, 10291, 10291, 10291, 10291, 10291,
10291, 10291, 10291, 10291, 10291, 10291, 12108, 12108,
0, 10292, 10293, 10293, 10294, 10294, 10294, 10294,
10295, 10295, 10295, 10295, 10295, 10295, 10295, 10295,
10296, 10296, 10296, 10296, 10296, 10296, 10296, 10296,
10296, 10296, 10296, 10296, 10296, 10296, 10296, 12107,
10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297,
10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297,
10297, 10297, 10297, 10297, 10297, 10297, 10297, 10297,
10297, 10297, 10297, 10297, 12109, 12109, 12109, 12109,
0, 10298, 10299, 10299, 10300, 10300, 10300, 10300,
10301, 10301, 10301, 10301, 10301, 10301, 10301, 10301,
10302, 10302, 10302, 10302, 10302, 10302, 10302, 10302,
10302, 10302, 10302, 10302, 10302, 10302, 10302, 12107,
10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303,
10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303,
10303, 10303, 10303, 10303, 10303, 10303, 10303, 10303,
10303, 10303, 10303, 10303, 10303, 10303, 12108, 12108,
10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304,
10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304,
10304, 10304, 10304, 10304, 10304, 10304, 10304, 10304,
10304, 10304, 10304, 10304, 10304, 10304, 10304, 12107,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
0, 0, 0, 0, 0, 0, 0, 10305,
0, 0, 0, 10306, 0, 10307, 10308, 10308,
0, 0, 0, 10309, 0, 10310, 10311, 10311,
0, 10312, 10313, 10313, 10314, 10314, 10314, 12107,
0, 0, 0, 10315, 0, 10316, 10317, 10317,
0, 10318, 10319, 10319, 10320, 10320, 10320, 10320,
0, 10321, 10322, 10322, 10323, 10323, 10323, 10323,
10324, 10324, 10324, 10324, 10324, 10324, 12108, 12108,
0, 0, 0, 10325, 0, 10326, 10327, 10327,
0, 10328, 10329, 10329, 10330, 10330, 10330, 10330,
0, 10331, 10332, 10332, 10333, 10333, 10333, 10333,
10334, 10334, 10334, 10334, 10334, 10334, 10334, 12107,
0, 10335, 10336, 10336, 10337, 10337, 10337, 10337,
10338, 10338, 10338, 10338, 10338, 10338, 10338, 10338,
10339, 10339, 10339, 10339, 10339, 10339, 10339, 10339,
10339, 10339, 10339, 10339, 12109, 12109, 12109, 12109,
0, 0, 0, 10340, 0, 10341, 10342, 10342,
0, 10343, 10344, 10344, 10345, 10345, 10345, 10345,
0, 10346, 10347, 10347, 10348, 10348, 10348, 10348,
10349, 10349, 10349, 10349, 10349, 10349, 10349, 12107,
0, 10350, 10351, 10351, 10352, 10352, 10352, 10352,
10353, 10353, 10353, 10353, 10353, 10353, 10353, 10353,
10354, 10354, 10354, 10354, 10354, 10354, 10354, 10354,
10354, 10354, 10354, 10354, 10354, 10354, 12108, 12108,
0, 10355, 10356, 10356, 10357, 10357, 10357, 10357,
10358, 10358, 10358, 10358, 10358, 10358, 10358, 10358,
10359, 10359, 10359, 10359, 10359, 10359, 10359, 10359,
10359, 10359, 10359, 10359, 10359, 10359, 10359, 12107,
10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360,
10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360,
10360, 10360, 10360, 10360, 10360, 10360, 10360, 10360,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10361, 0, 10362, 10363, 10363,
0, 10364, 10365, 10365, 10366, 10366, 10366, 10366,
0, 10367, 10368, 10368, 10369, 10369, 10369, 10369,
10370, 10370, 10370, 10370, 10370, 10370, 10370, 12107,
0, 10371, 10372, 10372, 10373, 10373, 10373, 10373,
10374, 10374, 10374, 10374, 10374, 10374, 10374, 10374,
10375, 10375, 10375, 10375, 10375, 10375, 10375, 10375,
10375, 10375, 10375, 10375, 10375, 10375, 12108, 12108,
0, 10376, 10377, 10377, 10378, 10378, 10378, 10378,
10379, 10379, 10379, 10379, 10379, 10379, 10379, 10379,
10380, 10380, 10380, 10380, 10380, 10380, 10380, 10380,
10380, 10380, 10380, 10380, 10380, 10380, 10380, 12107,
10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381,
10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381,
10381, 10381, 10381, 10381, 10381, 10381, 10381, 10381,
10381, 10381, 10381, 10381, 12109, 12109, 12109, 12109,
0, 10382, 10383, 10383, 10384, 10384, 10384, 10384,
10385, 10385, 10385, 10385, 10385, 10385, 10385, 10385,
10386, 10386, 10386, 10386, 10386, 10386, 10386, 10386,
10386, 10386, 10386, 10386, 10386, 10386, 10386, 12107,
10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387,
10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387,
10387, 10387, 10387, 10387, 10387, 10387, 10387, 10387,
10387, 10387, 10387, 10387, 10387, 10387, 12108, 12108,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 12107,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388,
10388, 10388, 10388, 10388, 10388, 10388, 10388, 10388,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 10389, 0, 10390, 10391, 10391,
0, 10392, 10393, 10393, 10394, 10394, 10394, 10394,
0, 10395, 10396, 10396, 10397, 10397, 10397, 10397,
10398, 10398, 10398, 10398, 10398, 10398, 10398, 12107,
0, 10399, 10400, 10400, 10401, 10401, 10401, 10401,
10402, 10402, 10402, 10402, 10402, 10402, 10402, 10402,
10403, 10403, 10403, 10403, 10403, 10403, 10403, 10403,
10403, 10403, 10403, 10403, 10403, 10403, 12108, 12108,
0, 10404, 10405, 10405, 10406, 10406, 10406, 10406,
10407, 10407, 10407, 10407, 10407, 10407, 10407, 10407,
10408, 10408, 10408, 10408, 10408, 10408, 10408, 10408,
10408, 10408, 10408, 10408, 10408, 10408, 10408, 12107,
10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409,
10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409,
10409, 10409, 10409, 10409, 10409, 10409, 10409, 10409,
10409, 10409, 10409, 10409, 12109, 12109, 12109, 12109,
0, 10410, 10411, 10411, 10412, 10412, 10412, 10412,
10413, 10413, 10413, 10413, 10413, 10413, 10413, 10413,
10414, 10414, 10414, 10414, 10414, 10414, 10414, 10414,
10414, 10414, 10414, 10414, 10414, 10414, 10414, 12107,
10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415,
10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415,
10415, 10415, 10415, 10415, 10415, 10415, 10415, 10415,
10415, 10415, 10415, 10415, 10415, 10415, 12108, 12108,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 12107,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
10416, 10416, 10416, 10416, 10416, 10416, 10416, 10416,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 10417, 10418, 10418, 10419, 10419, 10419, 10419,
10420, 10420, 10420, 10420, 10420, 10420, 10420, 10420,
10421, 10421, 10421, 10421, 10421, 10421, 10421, 10421,
10421, 10421, 10421, 10421, 10421, 10421, 10421, 12107,
10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422,
10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422,
10422, 10422, 10422, 10422, 10422, 10422, 10422, 10422,
10422, 10422, 10422, 10422, 10422, 10422, 12108, 12108,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 12107,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 10423, 10423, 10423, 10423,
10423, 10423, 10423, 10423, 12109, 12109, 12109, 12109,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
12114, 12114, 12114, 12114, 12114, 12114, 12114, 12114,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 12106,
0, 0, 0, 0, 0, 0, 0, 10426,
0, 0, 0, 10427, 0, 10428, 10429, 12107,
0, 0, 0, 0, 0, 0, 0, 10430,
0, 0, 0, 10431, 0, 10432, 10433, 12106,
0, 0, 0, 10434, 0, 10435, 10436, 10436,
0, 10437, 10438, 10438, 10439, 10439, 12108, 12108,
0, 0, 0, 0, 0, 0, 0, 10440,
0, 0, 0, 10441, 0, 10442, 10443, 12106,
0, 0, 0, 10444, 0, 10445, 10446, 10446,
0, 10447, 10448, 10448, 10449, 10449, 10449, 12107,
0, 0, 0, 10450, 0, 10451, 10452, 10452,
0, 10453, 10454, 10454, 10455, 10455, 10455, 12106,
0, 10456, 10457, 10457, 10458, 10458, 10458, 10458,
10459, 10459, 10459, 10459, 12109, 12109, 12109, 12109,
0, 0, 0, 0, 0, 0, 0, 10460,
0, 0, 0, 10461, 0, 10462, 10463, 12106,
0, 0, 0, 10464, 0, 10465, 10466, 10466,
0, 10467, 10468, 10468, 10469, 10469, 10469, 12107,
0, 0, 0, 10470, 0, 10471, 10472, 10472,
0, 10473, 10474, 10474, 10475, 10475, 10475, 12106,
0, 10476, 10477, 10477, 10478, 10478, 10478, 10478,
10479, 10479, 10479, 10479, 10479, 10479, 12108, 12108,
0, 0, 0, 10480, 0, 10481, 10482, 10482,
0, 10483, 10484, 10484, 10485, 10485, 10485, 12106,
0, 10486, 10487, 10487, 10488, 10488, 10488, 10488,
10489, 10489, 10489, 10489, 10489, 10489, 10489, 12107,
0, 10490, 10491, 10491, 10492, 10492, 10492, 10492,
10493, 10493, 10493, 10493, 10493, 10493, 10493, 12106,
10494, 10494, 10494, 10494, 10494, 10494, 10494, 10494,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 0, 0, 0, 0, 10495,
0, 0, 0, 10496, 0, 10497, 10498, 12106,
0, 0, 0, 10499, 0, 10500, 10501, 10501,
0, 10502, 10503, 10503, 10504, 10504, 10504, 12107,
0, 0, 0, 10505, 0, 10506, 10507, 10507,
0, 10508, 10509, 10509, 10510, 10510, 10510, 12106,
0, 10511, 10512, 10512, 10513, 10513, 10513, 10513,
10514, 10514, 10514, 10514, 10514, 10514, 12108, 12108,
0, 0, 0, 10515, 0, 10516, 10517, 10517,
0, 10518, 10519, 10519, 10520, 10520, 10520, 12106,
0, 10521, 10522, 10522, 10523, 10523, 10523, 10523,
10524, 10524, 10524, 10524, 10524, 10524, 10524, 12107,
0, 10525, 10526, 10526, 10527, 10527, 10527, 10527,
10528, 10528, 10528, 10528, 10528, 10528, 10528, 12106,
10529, 10529, 10529, 10529, 10529, 10529, 10529, 10529,
10529, 10529, 10529, 10529, 12109, 12109, 12109, 12109,
0, 0, 0, 10530, 0, 10531, 10532, 10532,
0, 10533, 10534, 10534, 10535, 10535, 10535, 12106,
0, 10536, 10537, 10537, 10538, 10538, 10538, 10538,
10539, 10539, 10539, 10539, 10539, 10539, 10539, 12107,
0, 10540, 10541, 10541, 10542, 10542, 10542, 10542,
10543, 10543, 10543, 10543, 10543, 10543, 10543, 12106,
10544, 10544, 10544, 10544, 10544, 10544, 10544, 10544,
10544, 10544, 10544, 10544, 10544, 10544, 12108, 12108,
0, 10545, 10546, 10546, 10547, 10547, 10547, 10547,
10548, 10548, 10548, 10548, 10548, 10548, 10548, 12106,
10549, 10549, 10549, 10549, 10549, 10549, 10549, 10549,
10549, 10549, 10549, 10549, 10549, 10549, 10549, 12107,
10550, 10550, 10550, 10550, 10550, 10550, 10550, 10550,
10550, 10550, 10550, 10550, 10550, 10550, 10550, 12106,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 0, 0, 0, 0, 10551,
0, 0, 0, 10552, 0, 10553, 10554, 12106,
0, 0, 0, 10555, 0, 10556, 10557, 10557,
0, 10558, 10559, 10559, 10560, 10560, 10560, 12107,
0, 0, 0, 10561, 0, 10562, 10563, 10563,
0, 10564, 10565, 10565, 10566, 10566, 10566, 12106,
0, 10567, 10568, 10568, 10569, 10569, 10569, 10569,
10570, 10570, 10570, 10570, 10570, 10570, 12108, 12108,
0, 0, 0, 10571, 0, 10572, 10573, 10573,
0, 10574, 10575, 10575, 10576, 10576, 10576, 12106,
0, 10577, 10578, 10578, 10579, 10579, 10579, 10579,
10580, 10580, 10580, 10580, 10580, 10580, 10580, 12107,
0, 10581, 10582, 10582, 10583, 10583, 10583, 10583,
10584, 10584, 10584, 10584, 10584, 10584, 10584, 12106,
10585, 10585, 10585, 10585, 10585, 10585, 10585, 10585,
10585, 10585, 10585, 10585, 12109, 12109, 12109, 12109,
0, 0, 0, 10586, 0, 10587, 10588, 10588,
0, 10589, 10590, 10590, 10591, 10591, 10591, 12106,
0, 10592, 10593, 10593, 10594, 10594, 10594, 10594,
10595, 10595, 10595, 10595, 10595, 10595, 10595, 12107,
0, 10596, 10597, 10597, 10598, 10598, 10598, 10598,
10599, 10599, 10599, 10599, 10599, 10599, 10599, 12106,
10600, 10600, 10600, 10600, 10600, 10600, 10600, 10600,
10600, 10600, 10600, 10600, 10600, 10600, 12108, 12108,
0, 10601, 10602, 10602, 10603, 10603, 10603, 10603,
10604, 10604, 10604, 10604, 10604, 10604, 10604, 12106,
10605, 10605, 10605, 10605, 10605, 10605, 10605, 10605,
10605, 10605, 10605, 10605, 10605, 10605, 10605, 12107,
10606, 10606, 10606, 10606, 10606, 10606, 10606, 10606,
10606, 10606, 10606, 10606, 10606, 10606, 10606, 12106,
10606, 10606, 10606, 10606, 10606, 10606, 10606, 10606,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10607, 0, 10608, 10609, 10609,
0, 10610, 10611, 10611, 10612, 10612, 10612, 12106,
0, 10613, 10614, 10614, 10615, 10615, 10615, 10615,
10616, 10616, 10616, 10616, 10616, 10616, 10616, 12107,
0, 10617, 10618, 10618, 10619, 10619, 10619, 10619,
10620, 10620, 10620, 10620, 10620, 10620, 10620, 12106,
10621, 10621, 10621, 10621, 10621, 10621, 10621, 10621,
10621, 10621, 10621, 10621, 10621, 10621, 12108, 12108,
0, 10622, 10623, 10623, 10624, 10624, 10624, 10624,
10625, 10625, 10625, 10625, 10625, 10625, 10625, 12106,
10626, 10626, 10626, 10626, 10626, 10626, 10626, 10626,
10626, 10626, 10626, 10626, 10626, 10626, 10626, 12107,
10627, 10627, 10627, 10627, 10627, 10627, 10627, 10627,
10627, 10627, 10627, 10627, 10627, 10627, 10627, 12106,
10627, 10627, 10627, 10627, 10627, 10627, 10627, 10627,
10627, 10627, 10627, 10627, 12109, 12109, 12109, 12109,
0, 10628, 10629, 10629, 10630, 10630, 10630, 10630,
10631, 10631, 10631, 10631, 10631, 10631, 10631, 12106,
10632, 10632, 10632, 10632, 10632, 10632, 10632, 10632,
10632, 10632, 10632, 10632, 10632, 10632, 10632, 12107,
10633, 10633, 10633, 10633, 10633, 10633, 10633, 10633,
10633, 10633, 10633, 10633, 10633, 10633, 10633, 12106,
10633, 10633, 10633, 10633, 10633, 10633, 10633, 10633,
10633, 10633, 10633, 10633, 10633, 10633, 12108, 12108,
10634, 10634, 10634, 10634, 10634, 10634, 10634, 10634,
10634, 10634, 10634, 10634, 10634, 10634, 10634, 12106,
10634, 10634, 10634, 10634, 10634, 10634, 10634, 10634,
10634, 10634, 10634, 10634, 10634, 10634, 10634, 12107,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
0, 0, 0, 0, 0, 0, 0, 10635,
0, 0, 0, 10636, 0, 10637, 10638, 12106,
0, 0, 0, 10639, 0, 10640, 10641, 10641,
0, 10642, 10643, 10643, 10644, 10644, 10644, 12107,
0, 0, 0, 10645, 0, 10646, 10647, 10647,
0, 10648, 10649, 10649, 10650, 10650, 10650, 12106,
0, 10651, 10652, 10652, 10653, 10653, 10653, 10653,
10654, 10654, 10654, 10654, 10654, 10654, 12108, 12108,
0, 0, 0, 10655, 0, 10656, 10657, 10657,
0, 10658, 10659, 10659, 10660, 10660, 10660, 12106,
0, 10661, 10662, 10662, 10663, 10663, 10663, 10663,
10664, 10664, 10664, 10664, 10664, 10664, 10664, 12107,
0, 10665, 10666, 10666, 10667, 10667, 10667, 10667,
10668, 10668, 10668, 10668, 10668, 10668, 10668, 12106,
10669, 10669, 10669, 10669, 10669, 10669, 10669, 10669,
10669, 10669, 10669, 10669, 12109, 12109, 12109, 12109,
0, 0, 0, 10670, 0, 10671, 10672, 10672,
0, 10673, 10674, 10674, 10675, 10675, 10675, 12106,
0, 10676, 10677, 10677, 10678, 10678, 10678, 10678,
10679, 10679, 10679, 10679, 10679, 10679, 10679, 12107,
0, 10680, 10681, 10681, 10682, 10682, 10682, 10682,
10683, 10683, 10683, 10683, 10683, 10683, 10683, 12106,
10684, 10684, 10684, 10684, 10684, 10684, 10684, 10684,
10684, 10684, 10684, 10684, 10684, 10684, 12108, 12108,
0, 10685, 10686, 10686, 10687, 10687, 10687, 10687,
10688, 10688, 10688, 10688, 10688, 10688, 10688, 12106,
10689, 10689, 10689, 10689, 10689, 10689, 10689, 10689,
10689, 10689, 10689, 10689, 10689, 10689, 10689, 12107,
10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690,
10690, 10690, 10690, 10690, 10690, 10690, 10690, 12106,
10690, 10690, 10690, 10690, 10690, 10690, 10690, 10690,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10691, 0, 10692, 10693, 10693,
0, 10694, 10695, 10695, 10696, 10696, 10696, 12106,
0, 10697, 10698, 10698, 10699, 10699, 10699, 10699,
10700, 10700, 10700, 10700, 10700, 10700, 10700, 12107,
0, 10701, 10702, 10702, 10703, 10703, 10703, 10703,
10704, 10704, 10704, 10704, 10704, 10704, 10704, 12106,
10705, 10705, 10705, 10705, 10705, 10705, 10705, 10705,
10705, 10705, 10705, 10705, 10705, 10705, 12108, 12108,
0, 10706, 10707, 10707, 10708, 10708, 10708, 10708,
10709, 10709, 10709, 10709, 10709, 10709, 10709, 12106,
10710, 10710, 10710, 10710, 10710, 10710, 10710, 10710,
10710, 10710, 10710, 10710, 10710, 10710, 10710, 12107,
10711, 10711, 10711, 10711, 10711, 10711, 10711, 10711,
10711, 10711, 10711, 10711, 10711, 10711, 10711, 12106,
10711, 10711, 10711, 10711, 10711, 10711, 10711, 10711,
10711, 10711, 10711, 10711, 12109, 12109, 12109, 12109,
0, 10712, 10713, 10713, 10714, 10714, 10714, 10714,
10715, 10715, 10715, 10715, 10715, 10715, 10715, 12106,
10716, 10716, 10716, 10716, 10716, 10716, 10716, 10716,
10716, 10716, 10716, 10716, 10716, 10716, 10716, 12107,
10717, 10717, 10717, 10717, 10717, 10717, 10717, 10717,
10717, 10717, 10717, 10717, 10717, 10717, 10717, 12106,
10717, 10717, 10717, 10717, 10717, 10717, 10717, 10717,
10717, 10717, 10717, 10717, 10717, 10717, 12108, 12108,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 12106,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 12107,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 10718,
10718, 10718, 10718, 10718, 10718, 10718, 10718, 12106,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 10719, 0, 10720, 10721, 10721,
0, 10722, 10723, 10723, 10724, 10724, 10724, 12106,
0, 10725, 10726, 10726, 10727, 10727, 10727, 10727,
10728, 10728, 10728, 10728, 10728, 10728, 10728, 12107,
0, 10729, 10730, 10730, 10731, 10731, 10731, 10731,
10732, 10732, 10732, 10732, 10732, 10732, 10732, 12106,
10733, 10733, 10733, 10733, 10733, 10733, 10733, 10733,
10733, 10733, 10733, 10733, 10733, 10733, 12108, 12108,
0, 10734, 10735, 10735, 10736, 10736, 10736, 10736,
10737, 10737, 10737, 10737, 10737, 10737, 10737, 12106,
10738, 10738, 10738, 10738, 10738, 10738, 10738, 10738,
10738, 10738, 10738, 10738, 10738, 10738, 10738, 12107,
10739, 10739, 10739, 10739, 10739, 10739, 10739, 10739,
10739, 10739, 10739, 10739, 10739, 10739, 10739, 12106,
10739, 10739, 10739, 10739, 10739, 10739, 10739, 10739,
10739, 10739, 10739, 10739, 12109, 12109, 12109, 12109,
0, 10740, 10741, 10741, 10742, 10742, 10742, 10742,
10743, 10743, 10743, 10743, 10743, 10743, 10743, 12106,
10744, 10744, 10744, 10744, 10744, 10744, 10744, 10744,
10744, 10744, 10744, 10744, 10744, 10744, 10744, 12107,
10745, 10745, 10745, 10745, 10745, 10745, 10745, 10745,
10745, 10745, 10745, 10745, 10745, 10745, 10745, 12106,
10745, 10745, 10745, 10745, 10745, 10745, 10745, 10745,
10745, 10745, 10745, 10745, 10745, 10745, 12108, 12108,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 12106,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 12107,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 12106,
10746, 10746, 10746, 10746, 10746, 10746, 10746, 10746,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 10747, 10748, 10748, 10749, 10749, 10749, 10749,
10750, 10750, 10750, 10750, 10750, 10750, 10750, 12106,
10751, 10751, 10751, 10751, 10751, 10751, 10751, 10751,
10751, 10751, 10751, 10751, 10751, 10751, 10751, 12107,
10752, 10752, 10752, 10752, 10752, 10752, 10752, 10752,
10752, 10752, 10752, 10752, 10752, 10752, 10752, 12106,
10752, 10752, 10752, 10752, 10752, 10752, 10752, 10752,
10752, 10752, 10752, 10752, 10752, 10752, 12108, 12108,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 12106,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 12107,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 12106,
10753, 10753, 10753, 10753, 10753, 10753, 10753, 10753,
10753, 10753, 10753, 10753, 12109, 12109, 12109, 12109,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 12106,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 12107,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 12106,
10754, 10754, 10754, 10754, 10754, 10754, 10754, 10754,
10754, 10754, 10754, 10754, 10754, 10754, 12108, 12108,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
12113, 12113, 12113, 12113, 12113, 12113, 12113, 12113,
0, 0, 0, 0, 0, 0, 0, 10755,
0, 0, 0, 10756, 0, 10757, 10758, 12106,
0, 0, 0, 10759, 0, 10760, 10761, 10761,
0, 10762, 10763, 10763, 10764, 10764, 10764, 12107,
0, 0, 0, 10765, 0, 10766, 10767, 10767,
0, 10768, 10769, 10769, 10770, 10770, 10770, 12106,
0, 10771, 10772, 10772, 10773, 10773, 10773, 10773,
10774, 10774, 10774, 10774, 10774, 10774, 12108, 12108,
0, 0, 0, 10775, 0, 10776, 10777, 10777,
0, 10778, 10779, 10779, 10780, 10780, 10780, 12106,
0, 10781, 10782, 10782, 10783, 10783, 10783, 10783,
10784, 10784, 10784, 10784, 10784, 10784, 10784, 12107,
0, 10785, 10786, 10786, 10787, 10787, 10787, 10787,
10788, 10788, 10788, 10788, 10788, 10788, 10788, 12106,
10789, 10789, 10789, 10789, 10789, 10789, 10789, 10789,
10789, 10789, 10789, 10789, 12109, 12109, 12109, 12109,
0, 0, 0, 10790, 0, 10791, 10792, 10792,
0, 10793, 10794, 10794, 10795, 10795, 10795, 12106,
0, 10796, 10797, 10797, 10798, 10798, 10798, 10798,
10799, 10799, 10799, 10799, 10799, 10799, 10799, 12107,
0, 10800, 10801, 10801, 10802, 10802, 10802, 10802,
10803, 10803, 10803, 10803, 10803, 10803, 10803, 12106,
10804, 10804, 10804, 10804, 10804, 10804, 10804, 10804,
10804, 10804, 10804, 10804, 10804, 10804, 12108, 12108,
0, 10805, 10806, 10806, 10807, 10807, 10807, 10807,
10808, 10808, 10808, 10808, 10808, 10808, 10808, 12106,
10809, 10809, 10809, 10809, 10809, 10809, 10809, 10809,
10809, 10809, 10809, 10809, 10809, 10809, 10809, 12107,
10810, 10810, 10810, 10810, 10810, 10810, 10810, 10810,
10810, 10810, 10810, 10810, 10810, 10810, 10810, 12106,
10810, 10810, 10810, 10810, 10810, 10810, 10810, 10810,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 0, 0, 10811, 0, 10812, 10813, 10813,
0, 10814, 10815, 10815, 10816, 10816, 10816, 12106,
0, 10817, 10818, 10818, 10819, 10819, 10819, 10819,
10820, 10820, 10820, 10820, 10820, 10820, 10820, 12107,
0, 10821, 10822, 10822, 10823, 10823, 10823, 10823,
10824, 10824, 10824, 10824, 10824, 10824, 10824, 12106,
10825, 10825, 10825, 10825, 10825, 10825, 10825, 10825,
10825, 10825, 10825, 10825, 10825, 10825, 12108, 12108,
0, 10826, 10827, 10827, 10828, 10828, 10828, 10828,
10829, 10829, 10829, 10829, 10829, 10829, 10829, 12106,
10830, 10830, 10830, 10830, 10830, 10830, 10830, 10830,
10830, 10830, 10830, 10830, 10830, 10830, 10830, 12107,
10831, 10831, 10831, 10831, 10831, 10831, 10831, 10831,
10831, 10831, 10831, 10831, 10831, 10831, 10831, 12106,
10831, 10831, 10831, 10831, 10831, 10831, 10831, 10831,
10831, 10831, 10831, 10831, 12109, 12109, 12109, 12109,
0, 10832, 10833, 10833, 10834, 10834, 10834, 10834,
10835, 10835, 10835, 10835, 10835, 10835, 10835, 12106,
10836, 10836, 10836, 10836, 10836, 10836, 10836, 10836,
10836, 10836, 10836, 10836, 10836, 10836, 10836, 12107,
10837, 10837, 10837, 10837, 10837, 10837, 10837, 10837,
10837, 10837, 10837, 10837, 10837, 10837, 10837, 12106,
10837, 10837, 10837, 10837, 10837, 10837, 10837, 10837,
10837, 10837, 10837, 10837, 10837, 10837, 12108, 12108,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 12106,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 12107,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 10838,
10838, 10838, 10838, 10838, 10838, 10838, 10838, 12106,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 0, 0, 10839, 0, 10840, 10841, 10841,
0, 10842, 10843, 10843, 10844, 10844, 10844, 12106,
0, 10845, 10846, 10846, 10847, 10847, 10847, 10847,
10848, 10848, 10848, 10848, 10848, 10848, 10848, 12107,
0, 10849, 10850, 10850, 10851, 10851, 10851, 10851,
10852, 10852, 10852, 10852, 10852, 10852, 10852, 12106,
10853, 10853, 10853, 10853, 10853, 10853, 10853, 10853,
10853, 10853, 10853, 10853, 10853, 10853, 12108, 12108,
0, 10854, 10855, 10855, 10856, 10856, 10856, 10856,
10857, 10857, 10857, 10857, 10857, 10857, 10857, 12106,
10858, 10858, 10858, 10858, 10858, 10858, 10858, 10858,
10858, 10858, 10858, 10858, 10858, 10858, 10858, 12107,
10859, 10859, 10859, 10859, 10859, 10859, 10859, 10859,
10859, 10859, 10859, 10859, 10859, 10859, 10859, 12106,
10859, 10859, 10859, 10859, 10859, 10859, 10859, 10859,
10859, 10859, 10859, 10859, 12109, 12109, 12109, 12109,
0, 10860, 10861, 10861, 10862, 10862, 10862, 10862,
10863, 10863, 10863, 10863, 10863, 10863, 10863, 12106,
10864, 10864, 10864, 10864, 10864, 10864, 10864, 10864,
10864, 10864, 10864, 10864, 10864, 10864, 10864, 12107,
10865, 10865, 10865, 10865, 10865, 10865, 10865, 10865,
10865, 10865, 10865, 10865, 10865, 10865, 10865, 12106,
10865, 10865, 10865, 10865, 10865, 10865, 10865, 10865,
10865, 10865, 10865, 10865, 10865, 10865, 12108, 12108,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 12106,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 12107,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 12106,
10866, 10866, 10866, 10866, 10866, 10866, 10866, 10866,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 10867, 10868, 10868, 10869, 10869, 10869, 10869,
10870, 10870, 10870, 10870, 10870, 10870, 10870, 12106,
10871, 10871, 10871, 10871, 10871, 10871, 10871, 10871,
10871, 10871, 10871, 10871, 10871, 10871, 10871, 12107,
10872, 10872, 10872, 10872, 10872, 10872, 10872, 10872,
10872, 10872, 10872, 10872, 10872, 10872, 10872, 12106,
10872, 10872, 10872, 10872, 10872, 10872, 10872, 10872,
10872, 10872, 10872, 10872, 10872, 10872, 12108, 12108,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 12106,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 12107,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 12106,
10873, 10873, 10873, 10873, 10873, 10873, 10873, 10873,
10873, 10873, 10873, 10873, 12109, 12109, 12109, 12109,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 12107,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 12108, 12108,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 12106,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 10874,
10874, 10874, 10874, 10874, 10874, 10874, 10874, 12107,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
12112, 12112, 12112, 12112, 12112, 12112, 12112, 12112,
0, 0, 0, 10875, 0, 10876, 10877, 10877,
0, 10878, 10879, 10879, 10880, 10880, 10880, 12106,
0, 10881, 10882, 10882, 10883, 10883, 10883, 10883,
10884, 10884, 10884, 10884, 10884, 10884, 10884, 12107,
0, 10885, 10886, 10886, 10887, 10887, 10887, 10887,
10888, 10888, 10888, 10888, 10888, 10888, 10888, 12106,
10889, 10889, 10889, 10889, 10889, 10889, 10889, 10889,
10889, 10889, 10889, 10889, 10889, 10889, 12108, 12108,
0, 10890, 10891, 10891, 10892, 10892, 10892, 10892,
10893, 10893, 10893, 10893, 10893, 10893, 10893, 12106,
10894, 10894, 10894, 10894, 10894, 10894, 10894, 10894,
10894, 10894, 10894, 10894, 10894, 10894, 10894, 12107,
10895, 10895, 10895, 10895, 10895, 10895, 10895, 10895,
10895, 10895, 10895, 10895, 10895, 10895, 10895, 12106,
10895, 10895, 10895, 10895, 10895, 10895, 10895, 10895,
10895, 10895, 10895, 10895, 12109, 12109, 12109, 12109,
0, 10896, 10897, 10897, 10898, 10898, 10898, 10898,
10899, 10899, 10899, 10899, 10899, 10899, 10899, 12106,
10900, 10900, 10900, 10900, 10900, 10900, 10900, 10900,
10900, 10900, 10900, 10900, 10900, 10900, 10900, 12107,
10901, 10901, 10901, 10901, 10901, 10901, 10901, 10901,
10901, 10901, 10901, 10901, 10901, 10901, 10901, 12106,
10901, 10901, 10901, 10901, 10901, 10901, 10901, 10901,
10901, 10901, 10901, 10901, 10901, 10901, 12108, 12108,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 12106,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 12107,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 12106,
10902, 10902, 10902, 10902, 10902, 10902, 10902, 10902,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
0, 10903, 10904, 10904, 10905, 10905, 10905, 10905,
10906, 10906, 10906, 10906, 10906, 10906, 10906, 12106,
10907, 10907, 10907, 10907, 10907, 10907, 10907, 10907,
10907, 10907, 10907, 10907, 10907, 10907, 10907, 12107,
10908, 10908, 10908, 10908, 10908, 10908, 10908, 10908,
10908, 10908, 10908, 10908, 10908, 10908, 10908, 12106,
10908, 10908, 10908, 10908, 10908, 10908, 10908, 10908,
10908, 10908, 10908, 10908, 10908, 10908, 12108, 12108,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 12106,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 12107,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 12106,
10909, 10909, 10909, 10909, 10909, 10909, 10909, 10909,
10909, 10909, 10909, 10909, 12109, 12109, 12109, 12109,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12107,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 12108, 12108,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12107,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 10910,
10910, 10910, 10910, 10910, 10910, 10910, 10910, 12106,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
12111, 12111, 12111, 12111, 12111, 12111, 12111, 12111,
0, 10911, 10912, 10912, 10913, 10913, 10913, 10913,
10914, 10914, 10914, 10914, 10914, 10914, 10914, 12106,
10915, 10915, 10915, 10915, 10915, 10915, 10915, 10915,
10915, 10915, 10915, 10915, 10915, 10915, 10915, 12107,
10916, 10916, 10916, 10916, 10916, 10916, 10916, 10916,
10916, 10916, 10916, 10916, 10916, 10916, 10916, 12106,
10916, 10916, 10916, 10916, 10916, 10916, 10916, 10916,
10916, 10916, 10916, 10916, 10916, 10916, 12108, 12108,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 12106,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 12107,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 12106,
10917, 10917, 10917, 10917, 10917, 10917, 10917, 10917,
10917, 10917, 10917, 10917, 12109, 12109, 12109, 12109,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12107,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 12108, 12108,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12107,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 12106,
10918, 10918, 10918, 10918, 10918, 10918, 10918, 10918,
12110, 12110, 12110, 12110, 12110, 12110, 12110, 12110,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115,
12115, 12115, 12115, 12115, 12115, 12115, 12115, 12115 };
static const uint16_t pairOtherVal[ 8192 ] = {
0, 0, 1, 0, 2, 1, 2, 0,
3, 3, 4, 1, 5, 2, 3, 3,
4, 6, 7, 4, 8, 5, 6, 6,
9, 7, 8, 8, 9, 9, 9, 9,
5, 10, 11, 10, 12, 11, 12, 12,
13, 13, 14, 14, 15, 15, 15, 15,
14, 16, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 19, 19, 19, 19,
6, 15, 16, 20, 17, 21, 22, 22,
18, 23, 24, 24, 25, 25, 25, 25,
19, 26, 27, 27, 28, 28, 28, 28,
29, 29, 29, 29, 29, 29, 29, 29,
20, 30, 31, 31, 32, 32, 32, 32,
33, 33, 33, 33, 33, 33, 33, 33,
34, 34, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 34, 34, 34, 34,
7, 21, 22, 35, 23, 36, 37, 37,
24, 38, 39, 39, 40, 40, 40, 40,
25, 41, 42, 42, 43, 43, 43, 43,
44, 44, 44, 44, 44, 44, 44, 44,
26, 45, 46, 46, 47, 47, 47, 47,
48, 48, 48, 48, 48, 48, 48, 48,
49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49,
27, 50, 51, 51, 52, 52, 52, 52,
53, 53, 53, 53, 53, 53, 53, 53,
54, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 54, 54, 54, 54, 54,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
8, 28, 29, 56, 30, 57, 58, 58,
31, 59, 60, 60, 61, 61, 61, 61,
32, 62, 63, 63, 64, 64, 64, 64,
65, 65, 65, 65, 65, 65, 65, 65,
33, 66, 67, 67, 68, 68, 68, 68,
69, 69, 69, 69, 69, 69, 69, 69,
70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70,
34, 71, 72, 72, 73, 73, 73, 73,
74, 74, 74, 74, 74, 74, 74, 74,
75, 75, 75, 75, 75, 75, 75, 75,
75, 75, 75, 75, 75, 75, 75, 75,
76, 76, 76, 76, 76, 76, 76, 76,
76, 76, 76, 76, 76, 76, 76, 76,
76, 76, 76, 76, 76, 76, 76, 76,
76, 76, 76, 76, 76, 76, 76, 76,
35, 77, 78, 78, 79, 79, 79, 79,
80, 80, 80, 80, 80, 80, 80, 80,
81, 81, 81, 81, 81, 81, 81, 81,
81, 81, 81, 81, 81, 81, 81, 81,
82, 82, 82, 82, 82, 82, 82, 82,
82, 82, 82, 82, 82, 82, 82, 82,
82, 82, 82, 82, 82, 82, 82, 82,
82, 82, 82, 82, 82, 82, 82, 82,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
83, 83, 83, 83, 83, 83, 83, 83,
9, 36, 37, 84, 38, 85, 86, 86,
39, 87, 88, 88, 89, 89, 89, 89,
40, 90, 91, 91, 92, 92, 92, 92,
93, 93, 93, 93, 93, 93, 93, 93,
41, 94, 95, 95, 96, 96, 96, 96,
97, 97, 97, 97, 97, 97, 97, 97,
98, 98, 98, 98, 98, 98, 98, 98,
98, 98, 98, 98, 98, 98, 98, 98,
42, 99, 100, 100, 101, 101, 101, 101,
102, 102, 102, 102, 102, 102, 102, 102,
103, 103, 103, 103, 103, 103, 103, 103,
103, 103, 103, 103, 103, 103, 103, 103,
104, 104, 104, 104, 104, 104, 104, 104,
104, 104, 104, 104, 104, 104, 104, 104,
104, 104, 104, 104, 104, 104, 104, 104,
104, 104, 104, 104, 104, 104, 104, 104,
43, 105, 106, 106, 107, 107, 107, 107,
108, 108, 108, 108, 108, 108, 108, 108,
109, 109, 109, 109, 109, 109, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109,
110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110,
110, 110, 110, 110, 110, 110, 110, 110,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
111, 111, 111, 111, 111, 111, 111, 111,
44, 112, 113, 113, 114, 114, 114, 114,
115, 115, 115, 115, 115, 115, 115, 115,
116, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116, 116, 116, 116, 116, 116,
117, 117, 117, 117, 117, 117, 117, 117,
117, 117, 117, 117, 117, 117, 117, 117,
117, 117, 117, 117, 117, 117, 117, 117,
117, 117, 117, 117, 117, 117, 117, 117,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
118, 118, 118, 118, 118, 118, 118, 118,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
119, 119, 119, 119, 119, 119, 119, 119,
10, 45, 46, 120, 47, 121, 122, 122,
48, 123, 124, 124, 125, 125, 125, 125,
49, 126, 127, 127, 128, 128, 128, 128,
129, 129, 129, 129, 129, 129, 129, 129,
50, 130, 131, 131, 132, 132, 132, 132,
133, 133, 133, 133, 133, 133, 133, 133,
134, 134, 134, 134, 134, 134, 134, 134,
134, 134, 134, 134, 134, 134, 134, 134,
51, 135, 136, 136, 137, 137, 137, 137,
138, 138, 138, 138, 138, 138, 138, 138,
139, 139, 139, 139, 139, 139, 139, 139,
139, 139, 139, 139, 139, 139, 139, 139,
140, 140, 140, 140, 140, 140, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140,
140, 140, 140, 140, 140, 140, 140, 140,
52, 141, 142, 142, 143, 143, 143, 143,
144, 144, 144, 144, 144, 144, 144, 144,
145, 145, 145, 145, 145, 145, 145, 145,
145, 145, 145, 145, 145, 145, 145, 145,
146, 146, 146, 146, 146, 146, 146, 146,
146, 146, 146, 146, 146, 146, 146, 146,
146, 146, 146, 146, 146, 146, 146, 146,
146, 146, 146, 146, 146, 146, 146, 146,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
147, 147, 147, 147, 147, 147, 147, 147,
53, 148, 149, 149, 150, 150, 150, 150,
151, 151, 151, 151, 151, 151, 151, 151,
152, 152, 152, 152, 152, 152, 152, 152,
152, 152, 152, 152, 152, 152, 152, 152,
153, 153, 153, 153, 153, 153, 153, 153,
153, 153, 153, 153, 153, 153, 153, 153,
153, 153, 153, 153, 153, 153, 153, 153,
153, 153, 153, 153, 153, 153, 153, 153,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
154, 154, 154, 154, 154, 154, 154, 154,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
155, 155, 155, 155, 155, 155, 155, 155,
54, 156, 157, 157, 158, 158, 158, 158,
159, 159, 159, 159, 159, 159, 159, 159,
160, 160, 160, 160, 160, 160, 160, 160,
160, 160, 160, 160, 160, 160, 160, 160,
161, 161, 161, 161, 161, 161, 161, 161,
161, 161, 161, 161, 161, 161, 161, 161,
161, 161, 161, 161, 161, 161, 161, 161,
161, 161, 161, 161, 161, 161, 161, 161,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
162, 162, 162, 162, 162, 162, 162, 162,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
163, 163, 163, 163, 163, 163, 163, 163,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
164, 164, 164, 164, 164, 164, 164, 164,
11, 55, 56, 165, 57, 166, 167, 167,
58, 168, 169, 169, 170, 170, 170, 170,
59, 171, 172, 172, 173, 173, 173, 173,
174, 174, 174, 174, 174, 174, 174, 174,
60, 175, 176, 176, 177, 177, 177, 177,
178, 178, 178, 178, 178, 178, 178, 178,
179, 179, 179, 179, 179, 179, 179, 179,
179, 179, 179, 179, 179, 179, 179, 179,
61, 180, 181, 181, 182, 182, 182, 182,
183, 183, 183, 183, 183, 183, 183, 183,
184, 184, 184, 184, 184, 184, 184, 184,
184, 184, 184, 184, 184, 184, 184, 184,
185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185,
185, 185, 185, 185, 185, 185, 185, 185,
62, 186, 187, 187, 188, 188, 188, 188,
189, 189, 189, 189, 189, 189, 189, 189,
190, 190, 190, 190, 190, 190, 190, 190,
190, 190, 190, 190, 190, 190, 190, 190,
191, 191, 191, 191, 191, 191, 191, 191,
191, 191, 191, 191, 191, 191, 191, 191,
191, 191, 191, 191, 191, 191, 191, 191,
191, 191, 191, 191, 191, 191, 191, 191,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
192, 192, 192, 192, 192, 192, 192, 192,
63, 193, 194, 194, 195, 195, 195, 195,
196, 196, 196, 196, 196, 196, 196, 196,
197, 197, 197, 197, 197, 197, 197, 197,
197, 197, 197, 197, 197, 197, 197, 197,
198, 198, 198, 198, 198, 198, 198, 198,
198, 198, 198, 198, 198, 198, 198, 198,
198, 198, 198, 198, 198, 198, 198, 198,
198, 198, 198, 198, 198, 198, 198, 198,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
199, 199, 199, 199, 199, 199, 199, 199,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
200, 200, 200, 200, 200, 200, 200, 200,
64, 201, 202, 202, 203, 203, 203, 203,
204, 204, 204, 204, 204, 204, 204, 204,
205, 205, 205, 205, 205, 205, 205, 205,
205, 205, 205, 205, 205, 205, 205, 205,
206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206,
206, 206, 206, 206, 206, 206, 206, 206,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
207, 207, 207, 207, 207, 207, 207, 207,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
208, 208, 208, 208, 208, 208, 208, 208,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
209, 209, 209, 209, 209, 209, 209, 209,
65, 210, 211, 211, 212, 212, 212, 212,
213, 213, 213, 213, 213, 213, 213, 213,
214, 214, 214, 214, 214, 214, 214, 214,
214, 214, 214, 214, 214, 214, 214, 214,
215, 215, 215, 215, 215, 215, 215, 215,
215, 215, 215, 215, 215, 215, 215, 215,
215, 215, 215, 215, 215, 215, 215, 215,
215, 215, 215, 215, 215, 215, 215, 215,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
216, 216, 216, 216, 216, 216, 216, 216,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
217, 217, 217, 217, 217, 217, 217, 217,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
218, 218, 218, 218, 218, 218, 218, 218,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
219, 219, 219, 219, 219, 219, 219, 219,
12, 66, 67, 220, 68, 221, 222, 222,
69, 223, 224, 224, 225, 225, 225, 225,
70, 226, 227, 227, 228, 228, 228, 228,
229, 229, 229, 229, 229, 229, 229, 229,
71, 230, 231, 231, 232, 232, 232, 232,
233, 233, 233, 233, 233, 233, 233, 233,
234, 234, 234, 234, 234, 234, 234, 234,
234, 234, 234, 234, 234, 234, 234, 234,
72, 235, 236, 236, 237, 237, 237, 237,
238, 238, 238, 238, 238, 238, 238, 238,
239, 239, 239, 239, 239, 239, 239, 239,
239, 239, 239, 239, 239, 239, 239, 239,
240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240,
240, 240, 240, 240, 240, 240, 240, 240,
73, 241, 242, 242, 243, 243, 243, 243,
244, 244, 244, 244, 244, 244, 244, 244,
245, 245, 245, 245, 245, 245, 245, 245,
245, 245, 245, 245, 245, 245, 245, 245,
246, 246, 246, 246, 246, 246, 246, 246,
246, 246, 246, 246, 246, 246, 246, 246,
246, 246, 246, 246, 246, 246, 246, 246,
246, 246, 246, 246, 246, 246, 246, 246,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
247, 247, 247, 247, 247, 247, 247, 247,
74, 248, 249, 249, 250, 250, 250, 250,
251, 251, 251, 251, 251, 251, 251, 251,
252, 252, 252, 252, 252, 252, 252, 252,
252, 252, 252, 252, 252, 252, 252, 252,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
253, 253, 253, 253, 253, 253, 253, 253,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
254, 254, 254, 254, 254, 254, 254, 254,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
75, 256, 257, 257, 258, 258, 258, 258,
259, 259, 259, 259, 259, 259, 259, 259,
260, 260, 260, 260, 260, 260, 260, 260,
260, 260, 260, 260, 260, 260, 260, 260,
261, 261, 261, 261, 261, 261, 261, 261,
261, 261, 261, 261, 261, 261, 261, 261,
261, 261, 261, 261, 261, 261, 261, 261,
261, 261, 261, 261, 261, 261, 261, 261,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
262, 262, 262, 262, 262, 262, 262, 262,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
263, 263, 263, 263, 263, 263, 263, 263,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
264, 264, 264, 264, 264, 264, 264, 264,
76, 265, 266, 266, 267, 267, 267, 267,
268, 268, 268, 268, 268, 268, 268, 268,
269, 269, 269, 269, 269, 269, 269, 269,
269, 269, 269, 269, 269, 269, 269, 269,
270, 270, 270, 270, 270, 270, 270, 270,
270, 270, 270, 270, 270, 270, 270, 270,
270, 270, 270, 270, 270, 270, 270, 270,
270, 270, 270, 270, 270, 270, 270, 270,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
271, 271, 271, 271, 271, 271, 271, 271,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
272, 272, 272, 272, 272, 272, 272, 272,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
273, 273, 273, 273, 273, 273, 273, 273,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
274, 274, 274, 274, 274, 274, 274, 274,
77, 275, 276, 276, 277, 277, 277, 277,
278, 278, 278, 278, 278, 278, 278, 278,
279, 279, 279, 279, 279, 279, 279, 279,
279, 279, 279, 279, 279, 279, 279, 279,
280, 280, 280, 280, 280, 280, 280, 280,
280, 280, 280, 280, 280, 280, 280, 280,
280, 280, 280, 280, 280, 280, 280, 280,
280, 280, 280, 280, 280, 280, 280, 280,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285, 285, 285, 285, 285, 285,
285, 285, 285
gitextract_p10ow7qd/
├── .gitignore
├── ACPCServer/
│ ├── LICENCE
│ ├── Makefile
│ ├── README
│ ├── README.submission
│ ├── acpc_play_match.pl
│ ├── all_in_expectation.c
│ ├── bm_run_matches.c
│ ├── bm_server.c
│ ├── bm_server.config
│ ├── bm_widget.c
│ ├── dealer.c
│ ├── evalHandTables
│ ├── example_player.c
│ ├── example_player.kuhn.limit.3p.sh
│ ├── example_player.limit.2p.sh
│ ├── example_player.limit.3p.sh
│ ├── example_player.nolimit.2p.sh
│ ├── example_player.nolimit.3p.sh
│ ├── game.c
│ ├── game.h
│ ├── holdem.limit.2p.reverse_blinds.game
│ ├── holdem.limit.3p.game
│ ├── holdem.nolimit.2p.reverse_blinds.game
│ ├── holdem.nolimit.3p.game
│ ├── kuhn.limit.3p.game
│ ├── leduc.game
│ ├── net.c
│ ├── net.h
│ ├── play_match.pl
│ ├── protocol.odt
│ ├── rng.c
│ ├── rng.h
│ ├── sum_values.pl
│ └── validate_submission.pl
├── Data/
│ ├── .gitignore
│ └── Models/
│ └── NoLimit/
│ ├── flop/
│ │ └── final_cpu.info
│ ├── preflop-aux/
│ │ ├── final_cpu.info
│ │ └── final_cpu.model
│ ├── river/
│ │ └── final_cpu.info
│ └── turn/
│ └── final_cpu.info
├── Source/
│ ├── ACPC/
│ │ ├── Tests/
│ │ │ └── test_parser.lua
│ │ ├── acpc_game.lua
│ │ ├── network_communication.lua
│ │ └── protocol_to_node.lua
│ ├── DataGeneration/
│ │ ├── aux_data_generation.lua
│ │ ├── data_generation.lua
│ │ ├── main_aux_data_generation.lua
│ │ ├── main_data_generation.lua
│ │ ├── random_card_generator.lua
│ │ └── range_generator.lua
│ ├── Game/
│ │ ├── Evaluation/
│ │ │ └── evaluator.lua
│ │ ├── bet_sizing.lua
│ │ ├── card_to_string_conversion.lua
│ │ └── card_tools.lua
│ ├── Lookahead/
│ │ ├── Tests/
│ │ │ ├── ranges/
│ │ │ │ ├── flop-situation1-p1.txt
│ │ │ │ ├── flop-situation1-p2.txt
│ │ │ │ ├── flop-situation2-p1.txt
│ │ │ │ ├── flop-situation2-p2.txt
│ │ │ │ ├── flop-situation3-p1.txt
│ │ │ │ ├── flop-situation3-p2.txt
│ │ │ │ ├── flop-situation4-p1.txt
│ │ │ │ ├── flop-situation4-p2.txt
│ │ │ │ ├── situation-p1.txt
│ │ │ │ ├── situation-p2.txt
│ │ │ │ ├── situation2-p1.txt
│ │ │ │ ├── situation2-p2.txt
│ │ │ │ ├── situation3-p1.txt
│ │ │ │ └── situation3-p2.txt
│ │ │ ├── test_flop_nl.lua
│ │ │ ├── test_preflop_nl.lua
│ │ │ ├── test_river_nl.lua
│ │ │ └── test_turn_nl.lua
│ │ ├── cfrd_gadget.lua
│ │ ├── lookahead.lua
│ │ ├── lookahead_builder.lua
│ │ ├── mock_resolving.lua
│ │ └── resolving.lua
│ ├── Nn/
│ │ ├── Bucketing/
│ │ │ ├── .gitignore
│ │ │ ├── flop_tools.lua
│ │ │ ├── river_tools.lua
│ │ │ └── turn_tools.lua
│ │ ├── bucket_conversion.lua
│ │ ├── bucketer.lua
│ │ ├── cpu_gpu_model_converter.lua
│ │ ├── masked_huber_loss.lua
│ │ ├── mock_nn_terminal.lua
│ │ ├── net_builder.lua
│ │ ├── next_round_value.lua
│ │ ├── next_round_value_pre.lua
│ │ ├── next_round_value_test.lua
│ │ └── value_nn.lua
│ ├── Player/
│ │ ├── continual_resolving.lua
│ │ ├── deepstack.lua
│ │ ├── deepstack_server.lua
│ │ ├── manual_player.lua
│ │ ├── slum_util.py
│ │ └── slumbot_player.py
│ ├── Settings/
│ │ ├── arguments.lua
│ │ ├── constants.lua
│ │ └── game_settings.lua
│ ├── TerminalEquity/
│ │ └── terminal_equity.lua
│ ├── Training/
│ │ ├── data_stream.lua
│ │ ├── main_train.lua
│ │ ├── raw_converter.lua
│ │ └── train.lua
│ ├── Tree/
│ │ ├── Tests/
│ │ │ ├── test_tree_builder.lua
│ │ │ ├── test_tree_cfr.lua
│ │ │ ├── test_tree_strategy_fillings.lua
│ │ │ ├── test_tree_values.lua
│ │ │ └── test_tree_visualiser.lua
│ │ ├── strategy_filling.lua
│ │ ├── tree_builder.lua
│ │ ├── tree_cfr.lua
│ │ ├── tree_strategy_filling.lua
│ │ ├── tree_values.lua
│ │ └── tree_visualiser.lua
│ └── tools.lua
├── readme.md
└── torch/
├── extra/
│ └── cutorch/
│ └── TensorMath.lua
└── pkg/
└── torch/
└── TensorMath.lua
SYMBOL INDEX (136 symbols across 13 files)
FILE: ACPCServer/all_in_expectation.c
function getUsedCards (line 21) | void getUsedCards( const Game *game,
function main (line 48) | int main( int argc, char **argv )
FILE: ACPCServer/bm_run_matches.c
function printUsage (line 21) | static void printUsage( FILE *file )
function main (line 69) | int main( int argc, char **argv )
FILE: ACPCServer/bm_server.c
type LLPoolEntry (line 40) | typedef struct LLPoolEntry_struct {
type LLPool (line 46) | typedef struct {
type BotSpec (line 54) | typedef struct {
type UserSpec (line 60) | typedef struct {
type GameConfig (line 66) | typedef struct {
type Config (line 78) | typedef struct {
type Connection (line 93) | typedef struct {
type Match (line 99) | typedef struct {
type MatchJob (line 116) | typedef struct {
type ServerState (line 124) | typedef struct {
function LLPool (line 138) | LLPool *newLLPool( const int dataSize )
function entryInList (line 151) | int entryInList( LLPoolEntry *list, LLPoolEntry *entry )
function LLPoolEntry (line 169) | LLPoolEntry *LLPoolAddItem( LLPool *pool, void *item )
function LLPoolRemoveEntry (line 202) | void LLPoolRemoveEntry( LLPool *pool, LLPoolEntry *entry )
function LLPoolEntry (line 231) | LLPoolEntry *LLPoolFirstEntry( LLPool *pool )
function LLPoolEntry (line 238) | LLPoolEntry *LLPoolNextEntry( LLPoolEntry *cur )
function printUsage (line 253) | void printUsage( FILE *file )
function setGameDefaults (line 258) | void setGameDefaults( GameConfig *gameConf )
function setDefaults (line 270) | void setDefaults( Config *conf )
function LLPoolEntry (line 283) | LLPoolEntry *findBot( const GameConfig *game, const char *name )
function addBot (line 299) | void addBot( GameConfig *gameConf, const char *spec )
function LLPoolEntry (line 332) | LLPoolEntry *findUser( const Config *conf, const char *name )
function addUser (line 348) | void addUser( Config *conf, const char *spec )
function LLPoolEntry (line 377) | LLPoolEntry *findGame( const Config *conf, const char *name )
function UserSpec (line 395) | UserSpec *validateLogon( const Config *conf, const char *line )
function readConfig (line 423) | void readConfig( const char *filename, Config *conf )
function addConnection (line 630) | void addConnection( ServerState *serv, const int sock )
function matchUsesConnection (line 646) | int matchUsesConnection( const Match *match, const LLPoolEntry *connEntry )
function closeConnection (line 662) | void closeConnection( ServerState *serv, LLPoolEntry *connEntry )
function handleListenSocket (line 682) | void handleListenSocket( const Config *conf, ServerState *serv )
function parseMatchSpec (line 700) | int parseMatchSpec( const Config *conf,
function writeHelpMessage (line 794) | void writeHelpMessage( int fd )
function writeGameList (line 806) | void writeGameList( const Config *conf, int fd )
function writeQueueStatus (line 831) | void writeQueueStatus( const Config *conf, const ServerState *serv, int ...
function handleConnection (line 858) | void handleConnection( Config *conf, ServerState *serv,
function timeIsEarlier (line 926) | int timeIsEarlier( struct timeval *a, struct timeval *b )
function botsInMatch (line 938) | int botsInMatch( const Match *match )
function startDealer (line 954) | void startDealer( const Config *conf,
function pid_t (line 1142) | pid_t startBot( const ServerState *serv,
function sendStartMessage (line 1181) | int sendStartMessage( const ServerState *serv,
function MatchJob (line 1211) | MatchJob runMatchJob( const Config *conf,
function startMatchJob (line 1277) | int startMatchJob( const Config *conf, ServerState *serv )
function initServerState (line 1377) | void initServerState( const Config *conf, ServerState *serv )
function checkIfJobFinished (line 1451) | int checkIfJobFinished( MatchJob *job )
function finishedJob (line 1498) | void finishedJob( ServerState *serv, LLPoolEntry *jobEntry )
function main (line 1509) | int main( int argc, char **argv )
FILE: ACPCServer/bm_widget.c
function printUsage (line 27) | static void printUsage( FILE *file )
function login (line 35) | int login( char *user, char *passwd, FILE *conn )
function main (line 47) | int main( int argc, char **argv )
FILE: ACPCServer/dealer.c
type ErrorInfo (line 46) | typedef struct {
function printUsage (line 58) | static void printUsage( FILE *file, int verbose )
function scanPortString (line 75) | static int scanPortString( const char *string,
function initErrorInfo (line 111) | static void initErrorInfo( const uint32_t maxInvalidActions,
function checkErrorInvalidAction (line 134) | static int checkErrorInvalidAction( const uint8_t seat, ErrorInfo *info )
function checkErrorTimes (line 147) | static int checkErrorTimes( const uint8_t seat,
function checkErrorNewHand (line 189) | static int checkErrorNewHand( const Game *game, ErrorInfo *info )
function seatToPlayer (line 201) | static uint8_t seatToPlayer( const Game *game, const uint8_t player0Seat,
function playerToSeat (line 207) | static uint8_t playerToSeat( const Game *game, const uint8_t player0Seat,
function sendPlayerMessage (line 214) | static int sendPlayerMessage( const Game *game, const MatchState *state,
function readPlayerResponse (line 257) | static int readPlayerResponse( const Game *game,
function setUpNewHand (line 372) | static int setUpNewHand( const Game *game, const uint8_t fixedSeats,
function processTransactionFile (line 396) | static int processTransactionFile( const Game *game, const int fixedSeats,
function logTransaction (line 482) | static int logTransaction( const Game *game, const State *state,
function checkVersion (line 520) | static int checkVersion( const uint8_t seat,
function addToLogFile (line 552) | static int addToLogFile( const Game *game, const State *state,
function printInitialMessage (line 614) | static int printInitialMessage( const char *matchName, const char *gameN...
function printFinalMessage (line 643) | static int printFinalMessage( const Game *game, char *seatName[ MAX_PLAY...
function gameLoop (line 719) | static int gameLoop( const Game *game, char *seatName[ MAX_PLAYERS ],
function main (line 902) | int main( int argc, char **argv )
FILE: ACPCServer/example_player.c
function main (line 20) | int main( int argc, char **argv )
FILE: ACPCServer/game.c
type ActionType (line 18) | enum ActionType
function consumeSpaces (line 107) | static int consumeSpaces( const char *string, int consumeEqual )
function readItems (line 125) | static int readItems( const char *itemFormat, const int numItems,
function Game (line 157) | Game *readGame( FILE *file )
function printGame (line 353) | void printGame( FILE *file, const Game *game )
function bcStart (line 438) | uint8_t bcStart( const Game *game, const uint8_t round )
function sumBoardCards (line 452) | uint8_t sumBoardCards( const Game *game, const uint8_t round )
function nextPlayer (line 465) | static uint8_t nextPlayer( const Game *game, const State *state,
function currentPlayer (line 479) | uint8_t currentPlayer( const Game *game, const State *state )
function numRaises (line 493) | uint8_t numRaises( const State *state )
function numFolded (line 508) | uint8_t numFolded( const Game *game, const State *state )
function numCalled (line 523) | uint8_t numCalled( const Game *game, const State *state )
function numAllIn (line 557) | uint8_t numAllIn( const Game *game, const State *state )
function numActingPlayers (line 572) | uint8_t numActingPlayers( const Game *game, const State *state )
function initState (line 588) | void initState( const Game *game, const uint32_t handId, State *state )
function dealCard (line 644) | static uint8_t dealCard( rng_state_t *rng, uint8_t *deck, const int numC...
function dealCards (line 656) | void dealCards( const Game *game, rng_state_t *rng, State *state )
function statesEqualCommon (line 694) | static int statesEqualCommon( const Game *game, const State *a,
function statesEqual (line 743) | int statesEqual( const Game *game, const State *a, const State *b )
function matchStatesEqual (line 764) | int matchStatesEqual( const Game *game, const MatchState *a,
function raiseIsValid (line 788) | int raiseIsValid( const Game *game, const State *curState,
function isValidAction (line 846) | int isValidAction( const Game *game, const State *curState,
function doAction (line 919) | void doAction( const Game *game, const Action *action, State *state )
function rankHand (line 1029) | static int rankHand( const Game *game, const State *state,
function valueOfState (line 1050) | double valueOfState( const Game *game, const State *state,
function readBetting (line 1185) | static int readBetting( const char *string, const Game *game, State *sta...
function printBetting (line 1227) | static int printBetting( const Game *game, const State *state,
function readHoleCards (line 1265) | static int readHoleCards( const char *string, const Game *game,
function printAllHoleCards (line 1298) | static int printAllHoleCards( const Game *game, const State *state,
function printPlayerHoleCards (line 1332) | static int printPlayerHoleCards( const Game *game, const State *state,
function readBoardCards (line 1384) | static int readBoardCards( const char *string, const Game *game,
function printBoardCards (line 1412) | static int printBoardCards( const Game *game, const State *state,
function readStateCommon (line 1448) | static int readStateCommon( const char *string, const Game *game,
function readState (line 1495) | int readState( const char *string, const Game *game, State *state )
function readMatchState (line 1515) | int readMatchState( const char *string, const Game *game,
function printStateCommon (line 1537) | static int printStateCommon( const Game *game, const State *state,
function printState (line 1569) | int printState( const Game *game, const State *state,
function printMatchState (line 1612) | int printMatchState( const Game *game, const MatchState *state,
function readAction (line 1657) | int readAction( const char *string, const Game *game, Action *action )
function printAction (line 1683) | int printAction( const Game *game, const Action *action,
function readCard (line 1715) | int readCard( const char *string, uint8_t *card )
function readCards (line 1742) | int readCards( const char *string, const int maxCards,
function printCard (line 1761) | int printCard( const uint8_t card, const int maxLen, char *string )
function printCards (line 1774) | int printCards( const int numCards, const uint8_t *cards,
FILE: ACPCServer/game.h
type BettingType (line 30) | enum BettingType { limitBetting, noLimitBetting }
type ActionType (line 31) | enum ActionType { a_fold = 0, a_call = 1, a_raise = 2,
type Action (line 34) | typedef struct {
type Game (line 40) | typedef struct {
type State (line 77) | typedef struct {
type MatchState (line 118) | typedef struct {
FILE: ACPCServer/net.c
function ReadBuf (line 15) | ReadBuf *createReadBuf( int fd )
function destroyReadBuf (line 30) | void destroyReadBuf( ReadBuf *readBuf )
function getLine (line 42) | ssize_t getLine( ReadBuf *readBuf,
function connectTo (line 130) | int connectTo( char *hostname, uint16_t port )
function getListenSocket (line 163) | int getListenSocket( uint16_t *desiredPort )
FILE: ACPCServer/net.h
type ReadBuf (line 24) | typedef struct {
FILE: ACPCServer/rng.c
function init_genrand (line 57) | void init_genrand( rng_state_t *state, uint32_t s )
function init_by_array (line 76) | void init_by_array( rng_state_t *state, uint32_t init_key[], int key_len...
function genrand_int32 (line 106) | uint32_t genrand_int32( rng_state_t *state )
FILE: ACPCServer/rng.h
type rng_state_t (line 27) | typedef struct {
FILE: Source/Player/slum_util.py
function acpcify_board (line 1) | def acpcify_board(board):
function acpcify_actions (line 10) | def acpcify_actions(actions):
Condensed preview — 121 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,036K chars).
[
{
"path": ".gitignore",
"chars": 22,
"preview": "**/a.out\n**/.DS_Store\n"
},
{
"path": "ACPCServer/LICENCE",
"chars": 1326,
"preview": "Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nPermission is hereby granted, free of ch"
},
{
"path": "ACPCServer/Makefile",
"chars": 838,
"preview": "CC = gcc\nCFLAGS = -O3 -Wall\n\nPROGRAMS = all_in_expectation bm_run_matches dealer example_player\n\nall: $(PROGRAMS)\n\nclean"
},
{
"path": "ACPCServer/README",
"chars": 4756,
"preview": "This README contains information about the server code for the Annual Computer\nPoker Competition. Please see the LICENC"
},
{
"path": "ACPCServer/README.submission",
"chars": 1620,
"preview": "#############################################################\n# Please fill out the following information about your tea"
},
{
"path": "ACPCServer/acpc_play_match.pl",
"chars": 2788,
"preview": "#!/usr/bin/perl\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse Socket;\nuse File:"
},
{
"path": "ACPCServer/all_in_expectation.c",
"chars": 5082,
"preview": "/*\nCopyright (C) 2014 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/bm_run_matches.c",
"chars": 7184,
"preview": "#include <stdlib.h>\n#include <stdio.h>\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n#include <assert.h>\n#include <"
},
{
"path": "ACPCServer/bm_server.c",
"chars": 38715,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/bm_server.config",
"chars": 2565,
"preview": "# port to connect to the server\nport 54000\n\n# maxmimum number of simultaneously locally running bots\n# 0 disables\nmaxRun"
},
{
"path": "ACPCServer/bm_widget.c",
"chars": 5176,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/dealer.c",
"chars": 32613,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/evalHandTables",
"chars": 217644,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n/* high card\t1287\t0\n pair\t\t3718\t"
},
{
"path": "ACPCServer/example_player.c",
"chars": 4842,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/example_player.kuhn.limit.3p.sh",
"chars": 54,
"preview": "#!/bin/bash\n./example_player kuhn.limit.3p.game $1 $2\n"
},
{
"path": "ACPCServer/example_player.limit.2p.sh",
"chars": 71,
"preview": "#!/bin/bash\n./example_player holdem.limit.2p.reverse_blinds.game $1 $2\n"
},
{
"path": "ACPCServer/example_player.limit.3p.sh",
"chars": 56,
"preview": "#!/bin/bash\n./example_player holdem.limit.3p.game $1 $2\n"
},
{
"path": "ACPCServer/example_player.nolimit.2p.sh",
"chars": 73,
"preview": "#!/bin/bash\n./example_player holdem.nolimit.2p.reverse_blinds.game $1 $2\n"
},
{
"path": "ACPCServer/example_player.nolimit.3p.sh",
"chars": 58,
"preview": "#!/bin/bash\n./example_player holdem.nolimit.3p.game $1 $2\n"
},
{
"path": "ACPCServer/game.c",
"chars": 39850,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <stdlib.h>\n#include <stdi"
},
{
"path": "ACPCServer/game.h",
"chars": 8553,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#ifndef _GAME_H\n#define _GAME_H\n#d"
},
{
"path": "ACPCServer/holdem.limit.2p.reverse_blinds.game",
"chars": 202,
"preview": "GAMEDEF\nlimit\nnumPlayers = 2\nnumRounds = 4\nblind = 10 5\nraiseSize = 10 10 20 20\nfirstPlayer = 2 1 1 1\nmaxRaises = 3 4 4 "
},
{
"path": "ACPCServer/holdem.limit.3p.game",
"chars": 204,
"preview": "GAMEDEF\nlimit\nnumPlayers = 3\nnumRounds = 4\nblind = 5 10 0\nraiseSize = 10 10 20 20\nfirstPlayer = 3 1 1 1\nmaxRaises = 3 4 "
},
{
"path": "ACPCServer/holdem.nolimit.2p.reverse_blinds.game",
"chars": 182,
"preview": "GAMEDEF\nnolimit\nnumPlayers = 2\nnumRounds = 4\nstack = 20000 20000\nblind = 50 100\nfirstPlayer = 1 2 2 2\nnumSuits = 4\nnumRa"
},
{
"path": "ACPCServer/holdem.nolimit.3p.game",
"chars": 190,
"preview": "GAMEDEF\nnolimit\nnumPlayers = 3\nnumRounds = 4\nstack = 20000 20000 20000\nblind = 50 100 0\nfirstPlayer = 3 1 1 1\nnumSuits ="
},
{
"path": "ACPCServer/kuhn.limit.3p.game",
"chars": 174,
"preview": "GAMEDEF\nlimit\nnumPlayers = 3\nnumRounds = 1\nblind = 1 1 1\nraiseSize = 1\nfirstPlayer = 1\nmaxRaises = 1\nnumSuits = 1\nnumRan"
},
{
"path": "ACPCServer/leduc.game",
"chars": 172,
"preview": "GAMEDEF\nnolimit\nnumPlayers = 2\nnumRounds = 2\nstack = 1200 1200\nblind = 100 100\nfirstPlayer = 1 1\nnumSuits = 2\nnumRanks ="
},
{
"path": "ACPCServer/net.c",
"chars": 4518,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#include <unistd.h>\n#include <netd"
},
{
"path": "ACPCServer/net.h",
"chars": 1690,
"preview": "/*\nCopyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n*/\n\n#ifndef _NET_H\n#define _NET_H\n\n#in"
},
{
"path": "ACPCServer/play_match.pl",
"chars": 2664,
"preview": "#!/usr/bin/perl\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse Socket;\n\n$hostnam"
},
{
"path": "ACPCServer/rng.c",
"chars": 5069,
"preview": "/* \n A C-program for MT19937, with initialization improved 2002/1/26.\n Coded by Takuji Nishimura and Makoto Matsumot"
},
{
"path": "ACPCServer/rng.h",
"chars": 2097,
"preview": "/*\n Copyright (C) 2011 by the Computer Poker Research Group, University of \n Alberta\n Copyright (C) 1997 - 2002, M"
},
{
"path": "ACPCServer/sum_values.pl",
"chars": 706,
"preview": "#!/usr/bin/perl\n\n#Copyright (C) 2014 by the Computer Poker Research Group, University of Alberta\n\nwhile( $_ = <> ) {\n\n "
},
{
"path": "ACPCServer/validate_submission.pl",
"chars": 19005,
"preview": "#!/usr/bin/perl -w\n\n# Copyright (C) 2011 by the Computer Poker Research Group, University of Alberta\n\nuse strict;\n\nuse P"
},
{
"path": "Data/.gitignore",
"chars": 46,
"preview": "Dot/\nTrainSamples/\n*epoch*.info\n*epoch*.model\n"
},
{
"path": "Source/ACPC/Tests/test_parser.lua",
"chars": 173,
"preview": "require \"ACPC.protocol_to_node\"\n\nlocal protocol_to_node = ACPCProtocolToNode()\nlocal state = protocol_to_node:parse_stat"
},
{
"path": "Source/ACPC/acpc_game.lua",
"chars": 3964,
"preview": "--- Handles communication to and from DeepStack using the ACPC protocol.\n--\n-- For details on the ACPC protocol, see\n-- "
},
{
"path": "Source/ACPC/network_communication.lua",
"chars": 1557,
"preview": "--- Handles network communication for DeepStack.\n-- \n-- Requires [luasocket](http://w3.impa.br/~diego/software/luasocket"
},
{
"path": "Source/ACPC/protocol_to_node.lua",
"chars": 16617,
"preview": "--- Converts between DeepStack's internal representation and the ACPC protocol\n-- used to communicate with the dealer.\n-"
},
{
"path": "Source/DataGeneration/aux_data_generation.lua",
"chars": 6970,
"preview": "--- Generates neural net training data by solving random poker situations.\n-- @module aux_data_generation\nlocal argument"
},
{
"path": "Source/DataGeneration/data_generation.lua",
"chars": 5672,
"preview": "--- Generates neural net training data by solving random poker situations.\n-- @module data_generation\nlocal arguments = "
},
{
"path": "Source/DataGeneration/main_aux_data_generation.lua",
"chars": 445,
"preview": "--- Script that generates training and validation files.\n-- @see data_generation\n-- @script main_data_generation\nlocal f"
},
{
"path": "Source/DataGeneration/main_data_generation.lua",
"chars": 433,
"preview": "--- Script that generates training and validation files.\n-- @see data_generation\n-- @script main_data_generation\nlocal f"
},
{
"path": "Source/DataGeneration/random_card_generator.lua",
"chars": 978,
"preview": "--- Samples random card combinations.\n-- @module random_card_generator\n\nrequire \"torch\"\nlocal M = {}\nlocal game_settings"
},
{
"path": "Source/DataGeneration/range_generator.lua",
"chars": 4454,
"preview": "--- Samples random probability vectors for use as player ranges.\n-- @classmod range_generator\n\nrequire \"math\"\nrequire \"t"
},
{
"path": "Source/Game/Evaluation/evaluator.lua",
"chars": 8273,
"preview": "--- Evaluates hand strength in Leduc Hold'em and variants.\n--\n-- Works with hands which contain two or three cards, but "
},
{
"path": "Source/Game/bet_sizing.lua",
"chars": 2908,
"preview": "--- Gives allowed bets during a game.\n-- Bets are restricted to be from a list of predefined fractions of the pot.\n-- @c"
},
{
"path": "Source/Game/card_to_string_conversion.lua",
"chars": 3273,
"preview": "--- Converts between string and numeric representations of cards.\n-- @module card_to_string_conversion\n\nrequire \"string\""
},
{
"path": "Source/Game/card_tools.lua",
"chars": 11548,
"preview": "--- A set of tools for basic operations on cards and sets of cards.\n--\n-- Several of the functions deal with \"range vect"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation1-p1.txt",
"chars": 12917,
"preview": "4d7c\t0.054927\n2c7c\t0.995828\n5d9c\t0.99831\n4dJc\t0.998619\n5d9h\t0.99831\n2s5s\t0.997305\n5d9s\t0.99831\n4dJs\t0.998619\n2c8c\t0.9967"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation1-p2.txt",
"chars": 11974,
"preview": "3s5c\t1.0\n4d7c\t1.0\n2c7c\t1.0\n4c9h\t1.0\n5d9c\t1.0\n4dJc\t1.0\n5d9h\t1.0\n2s5s\t1.0\n5d9s\t1.0\n4dJs\t1.0\n2c8c\t1.0\n4dTc\t1.0\n5d8c\t1.0\n4dT"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation2-p1.txt",
"chars": 12917,
"preview": "4d7c\t0.054927\n2c7c\t0.995828\n5d9c\t0.99831\n4dJc\t0.998619\n5d9h\t0.99831\n2s5s\t0.997305\n5d9s\t0.99831\n4dJs\t0.998619\n2c8c\t0.9967"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation2-p2.txt",
"chars": 280,
"preview": "6d7h\t0.830509\n6c7h\t0.830509\n6c7s\t0.830509\n6d7s\t0.830509\n6h7c\t0.830509\n6h7d\t0.830509\n6c7d\t0.830509\n6h7s\t0.830509\n6s7h\t0.8"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation3-p1.txt",
"chars": 13093,
"preview": "8s8h\t1.0\nAhAc\t0.99494\n4s4c\t1.0\n5sAs\t1.0\n9dQd\t0.999783\n9hAh\t1.0\nJhJc\t0.999812\nJsQs\t1.0\nJhJd\t0.999812\nKhKd\t0.99985\n9cAc\t1."
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation3-p2.txt",
"chars": 10278,
"preview": "8s8h\t1.0\nAhAc\t1.0\n4s4c\t1.0\n5sAs\t1.0\n9dQd\t1.0\n9hAh\t1.0\nJhJc\t1.0\nJsQs\t1.0\nJhJd\t1.0\nKhKd\t1.0\n9cAc\t1.0\nAsAh\t1.0\nTsTh\t1.0\nKsK"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation4-p1.txt",
"chars": 13289,
"preview": "4d4c\t1.0\nAdAc\t0.99494\n9h9c\t1.0\nAhAd\t0.99494\n9h9d\t1.0\nAsAd\t0.99494\n9sKs\t1.0\nKcAc\t1.0\nJhQh\t1.0\n9hQh\t0.999783\nAsAh\t0.99494\n"
},
{
"path": "Source/Lookahead/Tests/ranges/flop-situation4-p2.txt",
"chars": 10605,
"preview": "4d4c\t1.0\nAdAc\t1.0\n9h9c\t1.0\nAhAd\t1.0\n9h9d\t1.0\nAsAd\t1.0\n9sKs\t1.0\nKcAc\t1.0\nJhQh\t1.0\n9hQh\t1.0\nAsAh\t1.0\n8s8c\t1.0\nAsAc\t1.0\nJhJ"
},
{
"path": "Source/Lookahead/Tests/ranges/situation-p1.txt",
"chars": 2882,
"preview": "7hjh\t1.000\n6h7h\t1.000\n4s7s\t1.000\n9d9c\t1.000\n9s9d\t1.000\n6s7s\t1.000\ntsqs\t1.000\n9s9h\t1.000\n9s9c\t1.000\n4h7h\t1.000\n9h9c\t1.000"
},
{
"path": "Source/Lookahead/Tests/ranges/situation-p2.txt",
"chars": 1749,
"preview": "5d5c\t1\n5h5d\t1\n5h5c\t1\n7sas\t0.991\n7hah\t0.982\n8d8c\t0.969\n8h8c\t0.953\n8h8d\t0.953\n5h7h\t0.870\n7sks\t0.855\n7h9h\t0.834\n7s9s\t0.834\n"
},
{
"path": "Source/Lookahead/Tests/ranges/situation2-p1.txt",
"chars": 3549,
"preview": "TsAs\t0.012875\nQcAc\t0.192686\nQdAs\t0.177237\nQcAs\t0.177237\nQcAd\t0.184158\nQdAc\t0.184158\nQdAd\t0.192686\nJsAs\t0.005649\nKcAc\t0.1"
},
{
"path": "Source/Lookahead/Tests/ranges/situation2-p2.txt",
"chars": 4618,
"preview": "ThQh\t1.0\nTsAs\t1.0\nQcAc\t1.0\nQdAs\t1.0\nQcAs\t1.0\nQcAd\t1.0\nQdAc\t1.0\nQdAd\t1.0\nJsAs\t1.0\nKcAc\t0.999988\nKsAd\t0.99948\nKsAc\t0.99948"
},
{
"path": "Source/Lookahead/Tests/ranges/situation3-p1.txt",
"chars": 10166,
"preview": "7c9d\t0.576598\n7c9s\t0.576598\n8dQc\t0.004872\n8cQd\t0.081817\n8cQs\t0.081817\n8sQc\t0.004872\n2dKc\t0.735301\n2sKc\t0.735301\n2hQd\t0.2"
},
{
"path": "Source/Lookahead/Tests/ranges/situation3-p2.txt",
"chars": 12348,
"preview": "4s8c\t0.881958\n4d8c\t0.881958\n7c9d\t0.861573\n7c9s\t0.861573\n5c6h\t0.859565\n4c8d\t0.854665\n4c8s\t0.854665\n8dQc\t0.846896\n8cQd\t0.8"
},
{
"path": "Source/Lookahead/Tests/test_flop_nl.lua",
"chars": 3007,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = requ"
},
{
"path": "Source/Lookahead/Tests/test_preflop_nl.lua",
"chars": 2679,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = requ"
},
{
"path": "Source/Lookahead/Tests/test_river_nl.lua",
"chars": 3260,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = requ"
},
{
"path": "Source/Lookahead/Tests/test_turn_nl.lua",
"chars": 2985,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = requ"
},
{
"path": "Source/Lookahead/cfrd_gadget.lua",
"chars": 4181,
"preview": "--- Uses the the CFR-D gadget to generate opponent ranges for re-solving.\n--\n-- See [Solving Imperfect Information Games"
},
{
"path": "Source/Lookahead/lookahead.lua",
"chars": 19745,
"preview": "--- A depth-limited lookahead of the game tree used for re-solving.\n-- @classmod lookahead\n\nrequire 'Lookahead.lookahead"
},
{
"path": "Source/Lookahead/lookahead_builder.lua",
"chars": 26812,
"preview": "--- Builds the internal data structures of a @{lookahead|Lookahead} object.\n-- @classmod lookahead_builder\nlocal argumen"
},
{
"path": "Source/Lookahead/mock_resolving.lua",
"chars": 2417,
"preview": "--- Implements the re-solving interface used by @{resolving} with functions\n-- that do nothing.\n-- \n-- Used for debuggin"
},
{
"path": "Source/Lookahead/resolving.lua",
"chars": 6923,
"preview": "--- Implements depth-limited re-solving at a node of the game tree.\n-- Internally uses @{cfrd_gadget|CFRDGadget} TODO SO"
},
{
"path": "Source/Nn/Bucketing/.gitignore",
"chars": 12,
"preview": "unique*.dat\n"
},
{
"path": "Source/Nn/Bucketing/flop_tools.lua",
"chars": 1495,
"preview": "local M = {}\n\nfunction M:_suitcat_flop(s1,s2,s3,s4,s5)\n\tif(s1~=0) then return -1 end\n\n\tlocal ret = -1\n\n\tif(s2==0) then\n\t"
},
{
"path": "Source/Nn/Bucketing/river_tools.lua",
"chars": 3451,
"preview": "local arguments = require 'Settings.arguments'\n\nlocal M = {}\n\nfunction M:_suitcat_river(s1,s2,s3,s4,s5,s6,s7)\n\tlocal sui"
},
{
"path": "Source/Nn/Bucketing/turn_tools.lua",
"chars": 1995,
"preview": "local M = {}\n\nfunction M:_suitcat_turn(s1,s2,s3,s4,s5,s6)\n\tif s1~=0 then return -1 end\n\n\tlocal ret = -1\n\n\tif s2==0 then\n"
},
{
"path": "Source/Nn/bucket_conversion.lua",
"chars": 3391,
"preview": "--- Converts between vectors over private hands and vectors over buckets.\n-- @classmod bucket_conversion\n\nrequire 'torch"
},
{
"path": "Source/Nn/bucketer.lua",
"chars": 8705,
"preview": "--- Assigns hands to buckets on the given board.\n--\n-- For the Leduc implementation, we simply assign every possible set"
},
{
"path": "Source/Nn/cpu_gpu_model_converter.lua",
"chars": 1360,
"preview": "--- Generates a neural net model in CPU format from a neural net model saved\n-- in GPU format.\n-- @script cpu_gpu_model_"
},
{
"path": "Source/Nn/masked_huber_loss.lua",
"chars": 3342,
"preview": "--- Computes a Huber loss for neural net training and evaluation.\n--\n-- Computes the loss across buckets, but only on bu"
},
{
"path": "Source/Nn/mock_nn_terminal.lua",
"chars": 2332,
"preview": "--- Implements the same interface as @{value_nn}, but without uses terminal\n-- equity evaluation instead of a neural net"
},
{
"path": "Source/Nn/net_builder.lua",
"chars": 2572,
"preview": "--- Builds the neural net architecture.\n--\n-- Uses torch's [nn package](https://github.com/torch/nn/blob/master/README.m"
},
{
"path": "Source/Nn/next_round_value.lua",
"chars": 11951,
"preview": "--- Uses the neural net to estimate value at the end of the first betting round.\n-- @classmod next_round_value\n\nrequire "
},
{
"path": "Source/Nn/next_round_value_pre.lua",
"chars": 19704,
"preview": "--- Uses the neural net to estimate value at the end of the first betting round.\n-- @classmod next_round_value\n\nrequire "
},
{
"path": "Source/Nn/next_round_value_test.lua",
"chars": 1833,
"preview": "require 'Nn.next_round_value'\n--require 'Nn.mock_nn'\nrequire 'Nn.mock_nn_terminal'\nrequire 'TerminalEquity.terminal_equi"
},
{
"path": "Source/Nn/value_nn.lua",
"chars": 1897,
"preview": "--- Wraps the calls to the final neural net.\n-- @classmod value_nn\n\nrequire 'torch'\nrequire 'nn'\nlocal arguments = requi"
},
{
"path": "Source/Player/continual_resolving.lua",
"chars": 8847,
"preview": "--- Performs the main steps of continual re-solving, tracking player range\n-- and opponent counterfactual values so that"
},
{
"path": "Source/Player/deepstack.lua",
"chars": 1246,
"preview": "--- Performs the main loop for DeepStack.\n-- @script deepstack\n\nlocal arguments = require 'Settings.arguments'\nrequire \""
},
{
"path": "Source/Player/deepstack_server.lua",
"chars": 1779,
"preview": "--- Performs the main loop for DeepStack.\n-- @script deepstack\n\nlocal arguments = require 'Settings.arguments'\nlocal soc"
},
{
"path": "Source/Player/manual_player.lua",
"chars": 1123,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require \"Settings.constants\"\nrequire \"ACPC.acpc_game\"\n\n"
},
{
"path": "Source/Player/slum_util.py",
"chars": 1134,
"preview": "def acpcify_board(board):\n if len(board) == 6:\n return board\n if len(board) == 8:\n return board[:6] + \"/\" + boar"
},
{
"path": "Source/Player/slumbot_player.py",
"chars": 6690,
"preview": "from selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\nfrom selenium.webdriver.support.ui "
},
{
"path": "Source/Settings/arguments.lua",
"chars": 2309,
"preview": "--- Parameters for DeepStack.\n--@module arguments\n\nlocal torch = require 'torch'\n\ntorch.setdefaulttensortype('torch.Floa"
},
{
"path": "Source/Settings/constants.lua",
"chars": 1506,
"preview": "--- Various constants used in DeepStack.\n-- @module constants\n\nlocal constants = {}\n\n--- the number of players in the ga"
},
{
"path": "Source/Settings/game_settings.lua",
"chars": 659,
"preview": "--- Game constants which define the game played by DeepStack.\n-- @module game_settings\n\nrequire 'torch'\n\nlocal tools = r"
},
{
"path": "Source/TerminalEquity/terminal_equity.lua",
"chars": 12317,
"preview": "--- Evaluates player equities at terminal nodes of the game's public tree.\n-- @classmod terminal_equity\n\nrequire 'torch'"
},
{
"path": "Source/Training/data_stream.lua",
"chars": 5779,
"preview": "--- Handles the data used for neural net training and validation.\n-- @classmod data_stream\n\nrequire 'torch'\nlocal argume"
},
{
"path": "Source/Training/main_train.lua",
"chars": 614,
"preview": "--- Script that trains the neural network.\n--\n-- Uses data previously generated with @{data_generation_call}.\n-- @script"
},
{
"path": "Source/Training/raw_converter.lua",
"chars": 4913,
"preview": "if #arg == 0 then\n print(\"Please specify the street. 1 = preflop, 4 = river\")\n return\nend\n\nrequire 'torch'\nlocal argum"
},
{
"path": "Source/Training/train.lua",
"chars": 4223,
"preview": "--- Trains the neural network.\n--\n-- Uses data generated by @{data_generation_call}.\n-- @module train\n\nrequire 'optim'\nl"
},
{
"path": "Source/Tree/Tests/test_tree_builder.lua",
"chars": 559,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = req"
},
{
"path": "Source/Tree/Tests/test_tree_cfr.lua",
"chars": 1486,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal game_settings = requ"
},
{
"path": "Source/Tree/Tests/test_tree_strategy_fillings.lua",
"chars": 1419,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_tools = require"
},
{
"path": "Source/Tree/Tests/test_tree_values.lua",
"chars": 752,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = req"
},
{
"path": "Source/Tree/Tests/test_tree_visualiser.lua",
"chars": 668,
"preview": "local arguments = require 'Settings.arguments'\nlocal constants = require 'Settings.constants'\nlocal card_to_string = req"
},
{
"path": "Source/Tree/strategy_filling.lua",
"chars": 3091,
"preview": "--- Fills a game's public tree with a uniform strategy. In particular, fills\n-- the chance nodes with the probability of"
},
{
"path": "Source/Tree/tree_builder.lua",
"chars": 9709,
"preview": "--- Builds a public tree for Leduc Hold'em or variants.\n--\n-- Each node of the tree contains the following fields:\n--\n--"
},
{
"path": "Source/Tree/tree_cfr.lua",
"chars": 8451,
"preview": "--- Runs Counterfactual Regret Minimization (CFR) to approximately\n-- solve a game represented by a complete game tree.\n"
},
{
"path": "Source/Tree/tree_strategy_filling.lua",
"chars": 13227,
"preview": "--- Recursively performs continual re-solving at every node of a public tree to\n-- generate the DeepStack strategy for t"
},
{
"path": "Source/Tree/tree_values.lua",
"chars": 8219,
"preview": "--- Computes the expected value of a strategy profile on a game's public tree,\n-- as well as the value of a best respons"
},
{
"path": "Source/Tree/tree_visualiser.lua",
"chars": 7726,
"preview": "--- Generates visual representations of game trees.\n-- @classmod tree_visualiser\nlocal TreeVisualiser = torch.class('Tre"
},
{
"path": "Source/tools.lua",
"chars": 1221,
"preview": "--- Assorted tools.\n--@module tools\nlocal M = {C = {}, max_choose = 55}\n\n--- Generates a string representation of a tabl"
},
{
"path": "readme.md",
"chars": 6488,
"preview": "# DeepHoldem\n\nThis is an implementation of [DeepStack](https://www.deepstack.ai/s/DeepStack.pdf)\nfor No Limit Texas Hold"
},
{
"path": "torch/extra/cutorch/TensorMath.lua",
"chars": 74801,
"preview": "local wrap = require 'cwrap'\n\nlocal interface = wrap.CInterface.new()\nlocal method = wrap.CInterface.new()\nlocal argtype"
},
{
"path": "torch/pkg/torch/TensorMath.lua",
"chars": 54106,
"preview": "local wrap = require 'cwrap'\n\nrequire 'torchcwrap'\n\nlocal interface = wrap.CInterface.new()\nlocal method = wrap.CInterfa"
}
]
// ... and 6 more files (download for full content)
About this extraction
This page contains the full source code of the happypepper/DeepHoldem GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 121 files (63.7 MB), approximately 401.6k tokens, and a symbol index with 136 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.