OSDN Git Service

Merge branch 'master' into wdoor-stable
authorDaigo Moriwaki <daigo@debian.org>
Fri, 13 Dec 2013 08:34:16 +0000 (17:34 +0900)
committerDaigo Moriwaki <daigo@debian.org>
Fri, 13 Dec 2013 08:34:16 +0000 (17:34 +0900)
55 files changed:
README
changelog
csa-file-filter
mk_game_results
mk_html
mk_rate
mk_rate-from-grep [deleted file]
mk_rate-grep [deleted file]
shogi-server
shogi-server-profile [new file with mode: 0755]
shogi_server.rb
shogi_server/board.rb
shogi_server/command.rb
shogi_server/compatible.rb [new file with mode: 0644]
shogi_server/config.rb
shogi_server/game.rb
shogi_server/game_result.rb
shogi_server/handicapped_boards.rb
shogi_server/league.rb
shogi_server/league/floodgate.rb
shogi_server/league/floodgate_thread.rb
shogi_server/league/persistent.rb
shogi_server/login.rb
shogi_server/move.rb
shogi_server/pairing.rb
shogi_server/piece.rb
shogi_server/player.rb
shogi_server/timeout_queue.rb
shogi_server/util.rb
test/TC_ALL.rb
test/TC_before_agree.rb
test/TC_buoy.rb
test/TC_command.rb
test/TC_compatible.rb [new file with mode: 0644]
test/TC_floodgate.rb
test/TC_floodgate_history.rb
test/TC_floodgate_next_time_generator.rb
test/TC_functional.rb
test/TC_jishogi_kachi.rb
test/TC_league.rb
test/TC_move.rb
test/TC_not_sennichite.rb
test/TC_oute_sennichite.rb
test/TC_pairing.rb
test/TC_uchifuzume.rb
test/benchmark.rb
test/mock_player.rb
test/players.yaml
test/test.yaml
utils/correct-bug14635.rb
utils/csa-filter.rb
utils/eval_graph.rb
utils/players_graph.rb
utils/statistics.rb
webserver

diff --git a/README b/README
index baf9f8a..b746456 100644 (file)
--- a/README
+++ b/README
@@ -1,9 +1,5 @@
-$Id$
-
 = Shogi-server project
 
-2008-11-30 Daigo Moriwaki <daigo at debian dot org>
-
 The Shogi-server project develops Shogi-server, a rating tool and so on.
 
 == Shogi-server
@@ -14,15 +10,22 @@ in order for computer shogi players to play games.
 
 === Pre-requires
 
-Ruby 1.8.7:: Ruby 1.8.6 or earlier are not supported.
+Ruby 1.9.3 or 1.8.7
+
+As of January 2012, Shogi-server supports both Ruby 1.9.3 and 1.8.7. In
+future, however, it will only work with Ruby 1.9.x.  The Ruby community
+claimed that Ruby 1.8 had no future.  It is recommended that you soon
+upgrade to Ruby 1.9.3. 
 
 For Debian,
- $ sudo aptitude install ruby1.8
+ $ sudo aptitude install ruby1.9.1
+
+Note that the latest ruby1.9.1 package in Debian originates from Ruby 1.9.3.
+"1.9.1" in the package name is Ruby internal API version, not release version.
 
 === Install
 
- $ svn checkout \ 
-     http://svn.sourceforge.jp/svnroot/shogi-server/shogi-server/trunk shogi-server
+ $ git clone git://git.sourceforge.jp/gitroot/shogi-server/shogi-server.git
 
 The following files are required to run Shogi-server:
 
@@ -32,11 +35,17 @@ The following files are required to run Shogi-server:
 
 === Run
 
- $ ruby ./shogi-server --pid-file shogi-server.pid \
-                       --daemon . \
-                       --player-log-dir player-log-dir \
-                       --floodgate-history floodgate_history.yaml \
-                       floodgatetest 4000
+Examples:
+
+ $ ./shogi-server hoge 4000
+
+ $ ruby1.8 ./shogi-server hoge 4000
+
+ $ ruby1.9.1 ./shogi-server --pid-file shogi-server.pid \
+                            --daemon . \
+                            --player-log-dir player-log-dir \
+                            --floodgate-history floodgate_history.yaml \
+                            floodgatetest 4000
 
 == Other tools
 
@@ -45,3 +54,29 @@ See documents at the head of each source file.
 * mk_rate
 * mk_html
 * showgame
+
+
+== Tests
+
+Run the server
+
+  $ ./shogi-server hoge 4000
+
+Run test cases
+
+  $ cd test
+  $ ruby TC_ALL.rb
+
+Tested:
+
+- ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
+  Finished tests in 83.667928s, 4.2669 tests/s, 11.7249 assertions/s.
+  357 tests, 981 assertions, 0 failures, 0 errors, 0 skips
+
+- ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
+  Finished in 69.885457 seconds.
+  357 tests, 977 assertions, 0 failures, 0 errors
+
+  
+---
+2012-01-07 Daigo Moriwaki <daigo at debian dot org>
index 1764c67..d17e925 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,63 @@
+2013-12-13  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/league/floodgate_thread.rb:
+           - Added a log message.
+
+2013-12-08  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi-server/shogi_server/pairing.rb:
+           - Modified comment for LeastDiff match.
+           - Changed log messages and levels. 
+
+2013-12-07  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/pairing.rb, player.rb:
+           Simplify estimated rate of unrated players (less memory).
+         - Enhanced syntax of Floodgate time configuration file.
+           Now it supports "set sacrifice <player_id>"; it sets a
+           sacrificed player for a specific Floodgate game.
+           ex. set sacrifice gps500+e293220e3f8a3e59f79f6b0efffaa931
+
+2013-12-05  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - Added a new pairing method, ShogiServer::ExcludeUnratedPlayers,
+           which filters out unrated players.
+         - Enhanced syntax of Floodgate time configuration file.
+           Now it supports "set pairing_factory <function_name>"; it sets a
+           factory function name generating a pairing method which will be
+           used in a specific Floodgate game.
+           ex. set pairing_factory floodgate_zyunisen 
+
+2013-11-24  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/league/floodgate.rb: Improved robustness against
+           empty file under ruby 1.9.3p194
+         - shogi-server:
+           - Previously, reloading in daemon mode failed on
+             ruby 1.9.3p194. This issue has been fixed.
+           - Listen on only IPv4 explicitly. Under ruby 1.9.3p194, without
+             any bind addresses, ruby attempts to listen on both "0.0.0.0"
+             and "::". Specifying "::" on Linux leads to listen on both IPv4
+             and IPv6, which results in a warning message saying "Address
+             already in use - bind(2)".
+       * [mk_game_results]
+         - Fixed for reading Japanese comments under ruby1.9.3p194.
+       * mk_rate-from-grep, mk_rate-grep:
+         - Removed files that are no longer used.
+
+2013-11-23  Daigo Moriwaki <daigo at debian dot org>
+
+       * [mk_rate]
+         - gsl library may be provided as a gem
+         - Now duplicated inputs are checked and skipped.
+       * test/TC_floodgate.rb
+         - Improved randomness check so that it works on Ruby 2.0.0 as well
+
 2013-11-04  Daigo Moriwaki <daigo at debian dot org>
 
        * [mk_rate]
            + Improved the logic avoiding human-human match. Human-human
              matches will less likely happen.
 
+2012-01-07  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - Added shogi_server/compatible.rb, which implements compatible
+           methods and allows Ruby 1.8.7 to run the server.
+         - test/TC_floodgate.rb failed with Ruby 1.8.7. This issue has
+           been fixed.
+         - test/TC_uchifuzume.rb did not run with Ruby 1.8.7. This issue
+           has been fixed.
+         - test/TC_league.rb failed with Ruby 1.8.7. This issue has been
+           fixed.
+       * csa-file-filter,mk_game_results,mk_html,mk_rate:
+         - Updated documents in the command files.
+           Both Ruby 1.9.3 and 1.8.7 are supported.
+         - Make their shebang consistent (/usr/bin/ruby1.9.1)
+       * README:
+         - Both Ruby 1.9.3 and 1.8.7 are supported.
+       * Renewed year of copyright notice in each file.
+
+2012-01-06  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - test/TC_logger.rb depeneded on a specific directory where it was
+           running on. This issues has been fixed.
+
+2012-01-01  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/floodgate.rb: Generating next time around the new
+           year day by reading configuration files did not work correctly.
+           This issue has been fixed.
+
+2011-12-18  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server/board.rb, piece.rb: Refactoring to cache OU pieces,
+           which was inspired by 81SquareShogi-server's change
+           (74b24b88c843f1dd767412475b117481d1d5e8eb).
+         - Added shogi-server-profile to take profile of shogi-server.
+       * [mk_rate] [mk_game_results]
+         - Supports Ruby 1.9.3.
+
+2011-12-12  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - Support Ruby 1.9.3.
+         - Result of test/benchmark.rb
+           - Environment:
+             - CPU: AMD Athlon(tm) 64 X2 Dual Core Processor 4200+  
+             - RAM: 4GB
+             - OS: Debian Squeeze
+             - ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
+             - ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
+           - Server:  ruby1.8 (or ruby1.9.1) ./shogi-server hoge 4000
+           - Clients: ruby1.8 (or ruby1.9.1) -d ./benchmark.rb
+             csa/wdoor+floodgate-900-0+gps_normal+gps_l+20100507120007.csa 20
+           - Scores in seconds: (the smaller, the better)
+                           clients
+                           1.8.7   1.9.3
+             server 1.8.7  20 sec  21 sec
+                    1.9.3  26 sec  27 sec
+
 2010-10-06  Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
 
        * [shogi-server]
          - shogi_server/{board,command,game,league,player}.rb
-           The Buoy behaivor is changed.
+           The Buoy behavior is changed.
            + Starting a buoy game, players are notified a starting game
-             position with the initial position and moves, instread of a
+             position with the initial position and moves, instead of a
              targeting position.
            + Players are allowed to start buoy games with specific turns.
              ex. %%GAME buoy_foo-1500-0 +
        * [shogi-server]
          - shogi_server.rb, shogi_server/board.rb, shogi_server/move.rb
            - Refactoring: Board can now move_to() and move_back() a move
-             instread of deep_copy().
+             instead of deep_copy().
 
 2010-07-11  Daigo Moriwaki <daigo at debian dot org>
 
            .
            Note: Without this option, no floodgate games are started. If
            you want floodgate-900-0 to run, which was default enabled in
-           previous versions, you need to spefify the game name in this new
+           previous versions, you need to specify the game name in this new
            option.
          - Floodgate time configuration file:
            You need to set starting times of floodgate groups in
-           configuration files under the top directory. Each floodgat
-           e group requires a correspoding configuration file named
+           configuration files under the top directory. Each floodgate
+           group requires a corresponding configuration file named
            "<game_name>.conf". The file will be re-read once just after a
            game starts. 
            .
            floodgate-3600-30.conf.  However, for floodgate-900-0 and
            floodgate-3600-0, which were default enabled in previous
            versions, configuration files are optional if you are happy with
-           defualt time settings.
+           default time settings.
            File format is:
              Line format: 
                # This is a comment line
 2010-02-27  Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
-         - The server now provides more accurate time control. Previouslly,
+         - The server now provides more accurate time control. Previously,
            a player's thinking time included a time waiting to get the giant
            lock. This may have caused games to time up, especially, during
            byo-yomi etc.
 
        * [shogi-server]
          - shogi-server: The command line option --floodgate-history has
-           been deprectated. The server will decide history file names such
+           been deprecated. The server will decide history file names such
            as 'floodgate_history_900_0.yaml' and
            'floodgate_history_3600_0.yaml', and then put them in the top
            directory.
        * [shogi-server]
          - shogi_server/player.rb: Added new methods: is_human? and
            is_computer?. 
-           A human player is recommened to use a name ending with '_human'.  
+           A human player is recommended to use a name ending with '_human'.  
            ex. 'hoge_human', 'hoge_human@p1'
          - shogi_server/pairing.rb: Added a new class:
            StartGameWithoutHumans, which tries to make pairs trying to
-           avoid a human-human match. This is now enabled instread of the
+           avoid a human-human match. This is now enabled instead of the
            previous class: StartGame.
          - shogi-server, shogi_server/league/floodgate.rb:
            Changed the argument of Floodgate.new.
            which will be used to generate players.yaml. If the file does
            not exist, the server will create one automatically.
            Instruction to use the game result list file:
-           1. Make a list of game results from exisiting CSA files with
+           1. Make a list of game results from existing CSA files with
               mk_game_results
               % ./mk_game_results dir_of_csa_files > 00LIST
            2. Run the server. It appends a result of each game to
              - game_name is a valid game name with a prefix "buoy_".
              ex. buoy_foo-900-0
              - moves are initial moves from the Hirate position to a
-             spcific position that you want to start with.
+             specific position that you want to start with.
              ex. +7776FU-3334FU+8786FU
              - count is an optional attribute to tell how many times the
              game can be played (default 1). The count is decremented
 2009-06-18 Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
-         - An emtpy floodgate_history.yaml caused a server error. This
+         - An empty floodgate_history.yaml caused a server error. This
            issue has been fixed. 
            (Closes: #15124)
 
 
        * [mk_html]
          - Added a new option: --footer filename, which inserts contents of 
-           the filename at the bottom of a genrated page. A text specific to 
+           the filename at the bottom of a generated page. A text specific to 
            wdoor should be written by using this option. 
            (Closes: #14470)
          - It does no more depend on RDoc. RDoc::usage does not work well
 
        * [shogi-server]
          - Improved an existance check and etc. of directories specified
-           by command line options, expecially in case of the daemon mode. 
+           by command line options, especially in case of the daemon mode. 
            (Closes: #14244)
-         - A lotated log file is moved to $topdir/YYYY/MM/DD.
+         - A rotated log file is moved to $topdir/YYYY/MM/DD.
            (Closes: #14245)
 
 2008-11-27 Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
          - .csa files will be located in a sub directory such as
-           "2008/05/05/*.csa". Thease days, we have many games in a day. 
+           "2008/05/05/*.csa". These days, we have many games in a day. 
            This change will help users browse a file list.
 
 2008-05-03 Daigo Moriwaki <daigo at debian dot org>
index 681be6f..79d3a49 100755 (executable)
@@ -1,11 +1,11 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: Daigo Moriwaki
 # Homepage:: http://sourceforge.jp/projects/shogi-server/
 #
 #--
-# Copyright (C) 2008 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2008-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -50,9 +50,9 @@
 # 
 # Sample Command lines that isntall prerequires will work on Debian.
 # 
-# * Ruby 1.8.7 including RDoc
+# * Ruby 1.9.3 or 1.8.7 including RDoc
 # 
-#   $ sudo aptitude install ruby ruby1.8
+#   $ sudo aptitude install ruby ruby1.9.1
 # 
 # == Example
 #
index 432cf46..0da4ace 100755 (executable)
@@ -1,11 +1,11 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: Daigo Moriwaki
 # Homepage:: http://sourceforge.jp/projects/shogi-server/
 #
 #--
-# Copyright (C) 2009 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2009-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -35,9 +35,9 @@
 #
 # Sample Command lines that isntall prerequires will work on Debian.
 #
-# * Ruby 1.8.7
+# * Ruby 1.9.3 or 1.8.7
 #
-#   $ sudo aptitude install ruby1.8
+#   $ sudo aptitude install ruby1.9.1
 #
 # == Run
 #
@@ -58,7 +58,11 @@ require 'getoptlong'
 # @parameter file an absolute path of a csa file
 #
 def grep(file)
-  str = File.open(file).read
+  if RUBY_VERSION >= "1.9.1"
+    str = File.open(file, "r:EUC-JP").read
+  else
+    str = File.open(file, "r").read
+  end
 
   if /^N\+(.*)$/ =~ str then black_name = $1.strip end
   if /^N\-(.*)$/ =~ str then white_name = $1.strip end
diff --git a/mk_html b/mk_html
index 956be0a..e472670 100755 (executable)
--- a/mk_html
+++ b/mk_html
@@ -1,11 +1,11 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: Daigo Moriwaki
 # Homepage:: http://sourceforge.jp/projects/shogi-server/
 #
 #--
-# Copyright (C) 2006-2008 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2006-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -41,9 +41,9 @@
 #
 # == Prerequire
 #
-# * Ruby 1.8.7
+# * Ruby 1.9.3 or 1.8.7
 #
-#   $ sudo aptitude install ruby ruby1.8
+#   $ sudo aptitude install ruby ruby1.9.1
 #
 # == Example
 #
diff --git a/mk_rate b/mk_rate
index 3678b45..1f9e54a 100755 (executable)
--- a/mk_rate
+++ b/mk_rate
@@ -1,11 +1,11 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: Daigo Moriwaki
 # Homepage:: http://sourceforge.jp/projects/shogi-server/
 #
 #--
-# Copyright (C) 2006-2009 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2006-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 #
 # Sample Command lines that isntall prerequires will work on Debian.
 #
-# * Ruby 1.8.7
+# * Ruby 1.9.3 or 1.8.7 (including Rubygems)
 #
-#   $ sudo aptitude install ruby1.8
-#
-# * Rubygems
-#
-#   $ sudo aptitude install rubygems
+#   $ sudo aptitude install ruby1.9.1
 #
 # * Ruby bindings for the GNU Scientific Library (GSL[http://rb-gsl.rubyforge.org/])
 #
-#   $ sudo aptitude install libgsl-ruby1.8
+#   $ sudo aptitude install ruby-gsl
 #
 # * RGL: {Ruby Graph Library}[http://rubyforge.org/projects/rgl/]
 #
-#   $ sudo gem install rgl
+#   $ sudo gem1.9.1 install rgl
 #
 # == Examples
 #
 require 'yaml'
 require 'time'
 require 'getoptlong'
-require 'gsl'
+require 'set'
 require 'rubygems'
+require 'gsl'
 require 'rgl/adjacency'
 require 'rgl/connected_components'
 
@@ -127,6 +124,8 @@ DRAW_MARK = "draw"
 $players = Hash.new
 # Holds the last time when a player gamed
 $players_time = Hash.new { Time.at(0) }
+# Holds history of input lines to check duplicated inputs
+$history = Set.new
 
 
 #################################################
@@ -658,6 +657,12 @@ end
 # Parse a game result line
 #
 def parse(line)
+  if $history.include? line
+    $stderr.puts "[WARNING] Duplicated: #{line}"
+    return
+  end
+  $history.add line
+
   time, state, black_mark, black_id, white_id, white_mark, file = line.split("\t")
   unless time && state && black_mark && black_id &&
          white_id && white_mark && file
diff --git a/mk_rate-from-grep b/mk_rate-from-grep
deleted file mode 100755 (executable)
index 3c99c61..0000000
+++ /dev/null
@@ -1,796 +0,0 @@
-#!/usr/bin/ruby
-# $Id: mk_rate 316 2008-12-28 15:10:10Z beatles $
-#
-# Author:: Daigo Moriwaki
-# Homepage:: http://sourceforge.jp/projects/shogi-server/
-#
-#--
-# Copyright (C) 2006-2008 Daigo Moriwaki <daigo at debian dot org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#++
-#
-# == Synopsis
-#
-# mk_rate reads CSA files, calculates rating scores of each player, and then
-# outputs a yaml file (players.yaml) that Shogi-server can recognize.
-#
-# == Usage
-#
-# ./mk_rate [options] DIR..
-# 
-# DIR::
-#   CSA files are recursively looked up the directories.
-#
-# --half-life::
-#   n [days] (default 60)
-#   
-# --half-life-ignore::
-#   m [days] (default  7)
-#   after m days, the half-life effect works
-#
-# --ignore::
-#   m [days] (default  365*2)
-#   old files will be ignored
-#
-# --fixed-rate-player::
-#   player whose rate is fixed at the rate
-#
-# --fixed-rate::
-#   rate 
-#
-# --help::
-#   show this message
-#
-# == PREREQUIRE
-#
-# Sample Command lines that isntall prerequires will work on Debian.
-#
-# * Ruby 1.8.7
-#
-#   $ sudo aptitude install ruby1.8
-#
-# * Rubygems
-#
-#   $ sudo aptitude install rubygems
-#
-# * Ruby bindings for the GNU Scientific Library (GSL[http://rb-gsl.rubyforge.org/])
-#
-#   $ sudo aptitude install libgsl-ruby1.8
-#
-# * RGL: {Ruby Graph Library}[http://rubyforge.org/projects/rgl/]
-#
-#   $ sudo gem install rgl
-#
-# == Run
-#
-#   $ ./mk_rate . > players.yaml
-#
-# or, if you do not want the file to be update in case of errors, 
-#
-#   $ ./mk_rate . && ./mk_rate . > players.yaml
-#
-# == How players are rated
-#
-# The conditions that games and players are rated as following:
-#
-# * Rated games, which were played by both rated players.
-# * Rated players, who logged in the server with a name followed by a trip: "name,trip".
-# * (Rated) players, who played more than $GAMES_LIMIT [15] (rated) games. 
-#
-
-require 'yaml'
-require 'time'
-require 'getoptlong'
-require 'gsl'
-require 'rubygems'
-require 'rgl/adjacency'
-require 'rgl/connected_components'
-
-#################################################
-# Constants
-#
-
-# Count out players who play less games than $GAMES_LIMIT
-$GAMES_LIMIT = $DEBUG ? 0 : 15
-WIN_MARK  = "win"
-LOSS_MARK = "lose"
-DRAW_MARK = "draw"
-
-# Holds players
-$players = Hash.new
-# Holds the last time when a player gamed
-$players_time = Hash.new { Time.at(0) }
-
-
-#################################################
-# Keeps the value of the lowest key
-#
-class Record
-  def initialize
-    @lowest = []
-  end
-
-  def set(key, value)
-    if @lowest.empty? || key < @lowest[0]
-      @lowest = [key, value]
-    end
-  end
-
-  def get
-    if @lowest.empty?
-      nil
-    else
-      @lowest[1]
-    end
-  end
-end
-
-#################################################
-# Calculates rates of every player from a Win Loss GSL::Matrix
-#
-class Rating
-  include Math
-
-  # The model of the win possibility is 1/(1 + 10^(-d/400)).
-  # The equation in this class is 1/(1 + e^(-Kd)).
-  # So, K should be calculated like this.
-  K = Math.log(10.0) / 400.0
-  
-  # Convergence limit to stop Newton method.
-  ERROR_LIMIT = 1.0e-3
-  # Stop Newton method after this iterations.
-  COUNT_MAX = 500
-
-  # Average rate among the players
-  AVERAGE_RATE = 1000
-
-  
-  ###############
-  # Class methods
-  #  
-  
-  ##
-  # Calcurates the average of the vector.
-  #
-  def Rating.average(vector, mean=0.0)
-    sum = Array(vector).inject(0.0) {|sum, n| sum + n}
-    vector -= GSL::Vector[*Array.new(vector.size, sum/vector.size - mean)]
-    vector
-  end
-
-  ##################
-  # Instance methods
-  #
-  def initialize(win_loss_matrix)
-    @record = Record.new
-    @n = win_loss_matrix
-    case @n
-    when GSL::Matrix, GSL::Matrix::Int
-      @size = @n.size1
-    when ::Matrix
-      @size = @n.row_size
-    else
-      raise ArgumentError
-    end
-    initial_rate
-  end
-  attr_reader :rate, :n
-
-  def player_vector
-    GSL::Vector[*
-      (0...@size).collect {|k| yield k}
-    ]
-  end
-
-  def each_player
-    (0...@size).each {|k| yield k}
-  end
-
-  ##
-  # The possibility that the player k will beet the player i.
-  #
-  def win_rate(k,i)
-    1.0/(1.0 + exp(@rate[i]-@rate[k]))
-  end
-
-  ##
-  # Most possible equation
-  #
-  def func_vector
-    player_vector do|k| 
-      sum = 0.0
-      each_player do |i|
-        next if i == k
-        sum += @n[k,i] * win_rate(i,k) - @n[i,k] * win_rate(k,i) 
-      end
-      sum * 2.0
-    end
-  end
-
-  ##
-  #           / f0/R0 f0/R1 f0/R2 ... \
-  # dfk/dRj = | f1/R0 f1/R1 f1/R2 ... |
-  #           \ f2/R0 f2/R1 f2/R2 ... /
-  def d_func(k,j)
-    sum = 0.0
-    if k == j
-      each_player do |i|
-        next if i == k
-        sum += win_rate(i,k) * win_rate(k,i) * (@n[k,i] + @n[i,k])
-      end
-      sum *= -2.0
-    else # k != j
-      sum = 2.0 * win_rate(j,k) * win_rate(k,j) * (@n[k,j] + @n[j,k])
-    end
-    sum
-  end
-
-  ##
-  # Jacobi matrix of the func().
-  #   m00 m01
-  #   m10 m11
-  #
-  def j_matrix
-    GSL::Matrix[*
-      (0...@size).collect do |k|
-        (0...@size).collect do |j|
-          d_func(k,j)
-        end
-      end
-    ]
-  end
-
-  ##
-  # The initial value of the rate, which is of very importance for Newton
-  # method.  This is based on my huristics; the higher the win probablity of
-  # a player is, the greater points he takes.
-  #
-  def initial_rate
-    possibility = 
-      player_vector do |k|
-        v = GSL::Vector[0, 0]
-        each_player do |i|
-          next if k == i
-          v += GSL::Vector[@n[k,i], @n[i,k]]
-        end
-        v.nrm2 < 1 ? 0 : v[0] / (v[0] + v[1])
-      end
-    rank = possibility.sort_index
-    @rate = player_vector do |k|
-      K*500 * (rank[k]+1) / @size
-    end
-    average!
-  end
-
-  ##
-  # Resets @rate as the higher the current win probablity of a player is, 
-  # the greater points he takes. 
-  #
-  def initial_rate2
-    @rate = @record.get || @rate
-    rank = @rate.sort_index
-    @rate = player_vector do |k|
-      K*@count*1.5 * (rank[k]+1) / @size
-    end
-    average!
-  end
-
-  # mu is the deaccelrating parameter in Deaccelerated Newton method
-  def deaccelrate(mu, old_rate, a, old_f_nrm2)
-    @rate = old_rate - a * mu
-    if func_vector.nrm2 < (1 - mu / 4.0 ) * old_f_nrm2 then
-      return
-    end
-    if mu < 1e-4
-      @record.set(func_vector.nrm2, @rate)
-      initial_rate2
-      return
-    end
-    $stderr.puts "mu: %f " % [mu] if $DEBUG
-    deaccelrate(mu*0.5, old_rate, a, old_f_nrm2)
-  end
-
-  ##
-  # Main process to calculate ratings.
-  #
-  def rating
-    # Counter to stop the process. 
-    # Calulation in Newton method may fall in an infinite loop
-    @count = 0
-
-    # Main loop
-    begin
-      # Solve the equation: 
-      #   J*a=f
-      #   @rate_(n+1) = @rate_(n) - a
-      #
-      # f.nrm2 should approach to zero.
-      f = func_vector
-      j = j_matrix
-
-      # $stderr.puts "j: %s" % [j.inspect] if $DEBUG
-      $stderr.puts "f: %s -> %f" % [f.to_a.inspect, f.nrm2] if $DEBUG
-
-      # GSL::Linalg::LU.solve or GSL::Linalg::HH.solve would be available instead.
-      #a = GSL::Linalg::HH.solve(j, f)
-      a, = GSL::MultiFit::linear(j, f)
-      a = self.class.average(a)
-      # $stderr.puts "a: %s -> %f" % [a.to_a.inspect, a.nrm2] if $DEBUG
-      
-      # Deaccelerated Newton method
-      # GSL::Vector object should be immutable.
-      old_rate   = @rate
-      old_f      = f
-      old_f_nrm2 = old_f.nrm2
-      deaccelrate(1.0, old_rate, a, old_f_nrm2)
-      @record.set(func_vector.nrm2, @rate)
-
-      $stderr.printf "|error| : %5.2e\n", a.nrm2 if $DEBUG
-
-      @count += 1
-      if @count > COUNT_MAX
-        $stderr.puts "Values seem to oscillate. Stopped the process."
-        $stderr.puts "f: %s -> %f" % [func_vector.to_a.inspect, func_vector.nrm2]
-        break
-      end
-
-    end while (a.nrm2 > ERROR_LIMIT * @rate.nrm2)
-    
-    @rate = @record.get
-    $stderr.puts "resolved f: %s -> %f" %
-      [func_vector.to_a.inspect, func_vector.nrm2] if $DEBUG
-
-    @rate *= 1.0/K
-    finite!
-    self
-  end
-
-  ##
-  # Make the values of @rate finite.
-  #
-  def finite!
-    @rate = @rate.collect do |a|
-      if a.infinite?
-        a.infinite? * AVERAGE_RATE * 100
-      else
-        a
-      end
-    end
-  end
-
-  ##
-  # Flatten the values of @rate.
-  #
-  def average!(mean=0.0)
-    @rate = self.class.average(@rate, mean)
-  end
-
-  ##
-  # Translate by value
-  #
-  def translate!(value)
-    @rate += value
-  end
-
-  ##
-  # Make the values of @rate integer.
-  #
-  def integer!
-    @rate = @rate.collect do |a|
-      if a.finite?
-        a.to_i
-      elsif a.nan?
-        0
-      elsif a.infinite?
-        a.infinite? * AVERAGE_RATE * 100
-      end
-    end
-  end
-end
-
-#################################################
-# Encapsulate a pair of keys and win loss matrix.
-#   - keys is an array of player IDs; [gps+123, foo+234, ...]
-#   - matrix holds games # where player i (row index) beats player j (column index).
-#     The row and column indexes match with the keys.
-#
-# This object should be immutable. If an internal state is being modified, a
-# new object is always returned.
-#
-class WinLossMatrix
-
-  ###############
-  # Class methods
-  #  
-
-  def self.mk_matrix(players)
-    keys = players.keys.sort
-    size = keys.size
-    matrix =
-      GSL::Matrix[*
-      ((0...size).collect do |k|
-        p1 = keys[k]
-        p1_hash = players[p1]
-        ((0...size).collect do |j|
-          if k == j
-            0
-          else
-            p2 = keys[j]
-            v = p1_hash[p2] || Vector[0,0]
-            v[0]
-          end
-        end)
-      end)]
-    return WinLossMatrix.new(keys, matrix)
-  end
-
-  def self.mk_win_loss_matrix(players)
-    obj = mk_matrix(players)
-    return obj.filter
-  end
-
-  ##################
-  # Instance methods
-  #
-
-  # an array of player IDs; [gps+123, foo+234, ...]
-  attr_reader :keys
-
-  # matrix holds games # where player i (row index) beats player j (column index).
-  # The row and column indexes match with the keys.
-  attr_reader :matrix
-
-  def initialize(keys, matrix)
-    @keys   = keys
-    @matrix = matrix
-  end
-
-  ##
-  # Returns the size of the keys/matrix
-  #
-  def size
-    if @keys
-      @keys.size
-    else
-      nil
-    end
-  end
-
-  ##
-  # Removes players in a rows such as [1,3,5], and then returns a new
-  # object.
-  #
-  def delete_rows(rows)
-    rows = rows.sort.reverse
-
-    copied_cols = []
-    (0...size).each do |i|
-      next if rows.include?(i)
-      row = @matrix.row(i).clone
-      rows.each do |j|
-        row.delete_at(j)
-      end
-      copied_cols << row
-    end
-    if copied_cols.size == 0
-      new_matrix = GSL::Matrix.new
-    else
-      new_matrix = GSL::Matrix[*copied_cols]
-    end
-
-    new_keys = @keys.clone
-    rows.each do |j|
-      new_keys.delete_at(j)
-    end
-
-    return WinLossMatrix.new(new_keys, new_matrix)
-  end
-
-  ##
-  # Removes players who do not pass a criteria to be rated, and returns a
-  # new object.
-  # 
-  def filter
-    $stderr.puts @keys.inspect if $DEBUG
-    $stderr.puts @matrix.inspect if $DEBUG
-    delete = []  
-    (0...size).each do |i|
-      row = @matrix.row(i)
-      col = @matrix.col(i)
-      win  = row.sum
-      loss = col.sum
-      if win < 1 || loss < 1 || win + loss < $GAMES_LIMIT
-        delete << i
-      end
-    end
-
-    # The recursion ends if there is nothing to delete
-    return self if delete.empty?
-
-    new_obj = delete_rows(delete)
-    new_obj.filter
-  end
-
-  ##
-  # Cuts self into connecting groups such as each player in a group has at least
-  # one game with other players in the group. Returns them as an array.
-  #
-  def connected_subsets
-    g = RGL::AdjacencyGraph.new
-    (0...size).each do |k|
-      (0...size).each do |i|
-        next if k == i
-        if @matrix[k,i] > 0
-          g.add_edge(k,i)
-        end
-      end
-    end
-
-    subsets = []
-    g.each_connected_component do |c|
-      new_keys = []      
-      c.each do |v|
-        new_keys << keys[v.to_s.to_i]
-      end
-      subsets << new_keys
-    end
-
-    subsets = subsets.sort {|a,b| b.size <=> a.size}
-
-    result = subsets.collect do |keys|
-      matrix =
-        GSL::Matrix[*
-        ((0...keys.size).collect do |k|
-          p1 = @keys.index(keys[k])
-          ((0...keys.size).collect do |j|
-            if k == j
-              0
-            else
-              p2 = @keys.index(keys[j])
-              @matrix[p1,p2] + 0.001
-            end
-          end)
-        end)]
-      WinLossMatrix.new(keys, matrix)
-    end
-
-    return result
-  end
-
-  def to_s
-    "size : #{@keys.size}" + "\n" +
-    @keys.inspect + "\n" + 
-    @matrix.inspect
-  end
-
-end
-
-
-#################################################
-# Main methods
-#
-
-# Half-life effect
-# After NHAFE_LIFE days value will get half.
-# 0.693 is constant, where exp(0.693) ~ 0.5
-def half_life(days)
-  if days < $options["half-life-ignore"]
-    return 1.0
-  else
-    Math::exp(-0.693/$options["half-life"]*(days-$options["half-life-ignore"]))
-  end
-end
-
-def _add_win_loss(winner, loser, time)
-  how_long_days = (Time.now - time)/(3600*24)
-  $players[winner] ||= Hash.new { GSL::Vector[0,0] }
-  $players[loser]  ||= Hash.new { GSL::Vector[0,0] }
-  $players[winner][loser] += GSL::Vector[1.0*half_life(how_long_days),0]
-  $players[loser][winner] += GSL::Vector[0,1.0*half_life(how_long_days)]
-end
-
-def _add_time(player, time)
-  $players_time[player] = time if $players_time[player] < time
-end
-
-def add(black_mark, black_name, white_name, white_mark, time)
-  how_long_days = (Time.now - time)/(3600*24)
-  if (how_long_days > $options["ignore"])
-    return
-  end
-  if black_mark == WIN_MARK && white_mark == LOSS_MARK
-    _add_win_loss(black_name, white_name, time)
-  elsif black_mark == LOSS_MARK && white_mark == WIN_MARK
-    _add_win_loss(white_name, black_name, time)
-  elsif black_mark == DRAW_MARK && white_mark == DRAW_MARK
-    return
-  else
-    raise "Never reached!"
-  end
-  _add_time(black_name, time)
-  _add_time(white_name, time)
-end
-
-def identify_id(id)
-  if /@NORATE\+/ =~ id # the player having @NORATE in the name should not be rated
-    return nil
-  end
-  id.gsub(/@.*?\+/,"+")
-end
-
-def grep(str)
-  if /^([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([0-9]+)$/ =~ str.strip then
-    add($1,$2,$3,$4,Time.at($5.to_i))
-  end
-end
-
-def usage
-  $stderr.puts <<-EOF
-USAGE: #{$0} dir [...]
-  EOF
-  exit 1
-end
-
-def validate(yaml)
-  yaml["players"].each do |group_key, group|
-    group.each do |player_key, player|
-      rate = player['rate']
-      next unless rate
-      if rate > 10000 || rate < -10000
-        return false
-      end
-    end
-  end
-  return true
-end
-
-def usage(io)
-    io.puts <<EOF
-USAGE: #{$0} [options] DIR..
-  DIR                where CSA files are looked up recursively
-OPTOINS:
-  --half-life         n [days] (default 60)
-  --half-life-ignore  m [days] (default  7)
-                      after m days, half-life effect works
-  --fixed-rate-player player whose rate is fixed at the rate
-  --fixed-rate        rate 
-  --help              show this message
-EOF
-end
-
-def main
-  $options = Hash::new
-  parser = GetoptLong.new(
-    ["--half-life",         GetoptLong::REQUIRED_ARGUMENT],
-    ["--half-life-ignore",  GetoptLong::REQUIRED_ARGUMENT],
-    ["--ignore",  GetoptLong::REQUIRED_ARGUMENT],
-    ["--help", "-h",        GetoptLong::NO_ARGUMENT],
-    ["--fixed-rate-player", GetoptLong::REQUIRED_ARGUMENT],
-    ["--fixed-rate",        GetoptLong::REQUIRED_ARGUMENT])
-  parser.quiet = true
-  begin
-    parser.each_option do |name, arg|
-      name.sub!(/^--/, '')
-      $options[name] = arg.dup
-    end
-    if ( $options["fixed-rate-player"] && !$options["fixed-rate"]) ||
-       (!$options["fixed-rate-player"] &&  $options["fixed-rate"]) ||
-       ( $options["fixed-rate-player"] &&  $options["fixed-rate"].to_i <= 0) 
-      usage($stderr)
-      exit 1
-    end
-  rescue
-    usage($stderr)
-    raise parser.error_message
-  end
-  if $options["help"]
-    usage($stdout) 
-    exit 0
-  end
-  $options["half-life"] ||= 60
-  $options["half-life"] = $options["half-life"].to_i
-  $options["half-life-ignore"] ||= 7
-  $options["half-life-ignore"] = $options["half-life-ignore"].to_i
-  $options["ignore"] ||= 365*2
-  $options["ignore"] = $options["ignore"].to_i
-  $options["fixed-rate"] = $options["fixed-rate"].to_i if $options["fixed-rate"]
-
-  while line = $stdin.gets do
-    grep line.strip
-  end
-
-  yaml = {} 
-  yaml["players"] = {}
-  rating_group = 0
-  if $players.size > 0
-    obj = WinLossMatrix::mk_win_loss_matrix($players)
-    obj.connected_subsets.each do |win_loss_matrix|
-      yaml["players"][rating_group] = {}
-
-      rating = Rating.new(win_loss_matrix.matrix)
-      rating.rating
-      rating.average!(Rating::AVERAGE_RATE)
-      rating.integer!
-
-      if $options["fixed-rate-player"]
-        # first, try exact match
-        index = win_loss_matrix.keys.index($options["fixed-rate-player"])
-        # second, try regular match
-        unless index
-          win_loss_matrix.keys.each_with_index do |p, i|
-            if %r!#{$options["fixed-rate-player"]}! =~ p
-              index = i
-            end
-          end
-        end
-        if index
-          the_rate = rating.rate[index]
-          rating.translate!($options["fixed-rate"] - the_rate)
-        end
-      end
-
-      win_loss_matrix.keys.each_with_index do |p, i| # player_id, index#
-        win  = win_loss_matrix.matrix.row(i).sum
-        loss = win_loss_matrix.matrix.col(i).sum
-
-        yaml["players"][rating_group][p] = 
-          { 'name' => p.split("+")[0],
-            'rating_group' => rating_group,
-            'rate' => rating.rate[i],
-            'last_modified' => $players_time[p].dup,
-            'win'  => win,
-            'loss' => loss}
-      end
-      rating_group += 1
-    end
-  end
-  rating_group -= 1
-  non_rated_group = 999 # large enough
-  yaml["players"][non_rated_group] = {}
-  $players.each_key do |id|
-    # skip players who have already been rated
-    found = false
-    (0..rating_group).each do |i|
-       found = true if yaml["players"][i][id]
-       break if found
-    end
-    next if found
-
-    v = GSL::Vector[0, 0]
-    $players[id].each_value {|value| v += value}
-    next if v[0] < 1 && v[1] < 1
-
-    yaml["players"][non_rated_group][id] =
-      { 'name' => id.split("+")[0],
-        'rating_group' => non_rated_group,
-        'rate' => 0,
-        'last_modified' => $players_time[id].dup,
-        'win'  => v[0],
-        'loss' => v[1]}
-  end
-  unless validate(yaml)
-    $stderr.puts "Aborted. It did not result in valid ratings."
-    $stderr.puts yaml.to_yaml if $DEBUG
-    exit 10
-  end
-  puts yaml.to_yaml
-end
-
-if __FILE__ == $0
-  main
-end
-
-# vim: ts=2 sw=2 sts=0
diff --git a/mk_rate-grep b/mk_rate-grep
deleted file mode 100755 (executable)
index 2f8b748..0000000
+++ /dev/null
@@ -1,747 +0,0 @@
-#!/usr/bin/ruby
-# $Id: mk_rate 316 2008-12-28 15:10:10Z beatles $
-#
-# Author:: Daigo Moriwaki
-# Homepage:: http://sourceforge.jp/projects/shogi-server/
-#
-#--
-# Copyright (C) 2006-2008 Daigo Moriwaki <daigo at debian dot org>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-#++
-#
-# == Synopsis
-#
-# mk_rate reads CSA files, calculates rating scores of each player, and then
-# outputs a yaml file (players.yaml) that Shogi-server can recognize.
-#
-# == Usage
-#
-# ./mk_rate [options] DIR..
-# 
-# DIR::
-#   CSA files are recursively looked up the directories.
-#
-# --half-life::
-#   n [days] (default 60)
-#   
-# --half-life-ignore::
-#   m [days] (default  7)
-#   after m days, the half-life effect works
-#
-# --fixed-rate-player::
-#   player whose rate is fixed at the rate
-#
-# --fixed-rate::
-#   rate 
-#
-# --help::
-#   show this message
-#
-# == PREREQUIRE
-#
-# Sample Command lines that isntall prerequires will work on Debian.
-#
-# * Ruby 1.8.7
-#
-#   $ sudo aptitude install ruby1.8
-#
-# * Rubygems
-#
-#   $ sudo aptitude install rubygems
-#
-# * Ruby bindings for the GNU Scientific Library (GSL[http://rb-gsl.rubyforge.org/])
-#
-#   $ sudo aptitude install libgsl-ruby1.8
-#
-# * RGL: {Ruby Graph Library}[http://rubyforge.org/projects/rgl/]
-#
-#   $ sudo gem install rgl
-#
-# == Run
-#
-#   $ ./mk_rate . > players.yaml
-#
-# or, if you do not want the file to be update in case of errors, 
-#
-#   $ ./mk_rate . && ./mk_rate . > players.yaml
-#
-# == How players are rated
-#
-# The conditions that games and players are rated as following:
-#
-# * Rated games, which were played by both rated players.
-# * Rated players, who logged in the server with a name followed by a trip: "name,trip".
-# * (Rated) players, who played more than $GAMES_LIMIT [15] (rated) games. 
-#
-
-require 'yaml'
-require 'time'
-require 'getoptlong'
-require 'gsl'
-require 'rubygems'
-require 'rgl/adjacency'
-require 'rgl/connected_components'
-
-#################################################
-# Constants
-#
-
-# Count out players who play less games than $GAMES_LIMIT
-$GAMES_LIMIT = $DEBUG ? 0 : 15
-WIN_MARK  = "win"
-LOSS_MARK = "lose"
-DRAW_MARK = "draw"
-
-# Holds players
-$players = Hash.new
-# Holds the last time when a player gamed
-$players_time = Hash.new { Time.at(0) }
-
-
-#################################################
-# Keeps the value of the lowest key
-#
-class Record
-  def initialize
-    @lowest = []
-  end
-
-  def set(key, value)
-    if @lowest.empty? || key < @lowest[0]
-      @lowest = [key, value]
-    end
-  end
-
-  def get
-    if @lowest.empty?
-      nil
-    else
-      @lowest[1]
-    end
-  end
-end
-
-#################################################
-# Calculates rates of every player from a Win Loss GSL::Matrix
-#
-class Rating
-  include Math
-
-  # The model of the win possibility is 1/(1 + 10^(-d/400)).
-  # The equation in this class is 1/(1 + e^(-Kd)).
-  # So, K should be calculated like this.
-  K = Math.log(10.0) / 400.0
-  
-  # Convergence limit to stop Newton method.
-  ERROR_LIMIT = 1.0e-3
-  # Stop Newton method after this iterations.
-  COUNT_MAX = 500
-
-  # Average rate among the players
-  AVERAGE_RATE = 1000
-
-  
-  ###############
-  # Class methods
-  #  
-  
-  ##
-  # Calcurates the average of the vector.
-  #
-  def Rating.average(vector, mean=0.0)
-    sum = Array(vector).inject(0.0) {|sum, n| sum + n}
-    vector -= GSL::Vector[*Array.new(vector.size, sum/vector.size - mean)]
-    vector
-  end
-
-  ##################
-  # Instance methods
-  #
-  def initialize(win_loss_matrix)
-    @record = Record.new
-    @n = win_loss_matrix
-    case @n
-    when GSL::Matrix, GSL::Matrix::Int
-      @size = @n.size1
-    when ::Matrix
-      @size = @n.row_size
-    else
-      raise ArgumentError
-    end
-    initial_rate
-  end
-  attr_reader :rate, :n
-
-  def player_vector
-    GSL::Vector[*
-      (0...@size).collect {|k| yield k}
-    ]
-  end
-
-  def each_player
-    (0...@size).each {|k| yield k}
-  end
-
-  ##
-  # The possibility that the player k will beet the player i.
-  #
-  def win_rate(k,i)
-    1.0/(1.0 + exp(@rate[i]-@rate[k]))
-  end
-
-  ##
-  # Most possible equation
-  #
-  def func_vector
-    player_vector do|k| 
-      sum = 0.0
-      each_player do |i|
-        next if i == k
-        sum += @n[k,i] * win_rate(i,k) - @n[i,k] * win_rate(k,i) 
-      end
-      sum * 2.0
-    end
-  end
-
-  ##
-  #           / f0/R0 f0/R1 f0/R2 ... \
-  # dfk/dRj = | f1/R0 f1/R1 f1/R2 ... |
-  #           \ f2/R0 f2/R1 f2/R2 ... /
-  def d_func(k,j)
-    sum = 0.0
-    if k == j
-      each_player do |i|
-        next if i == k
-        sum += win_rate(i,k) * win_rate(k,i) * (@n[k,i] + @n[i,k])
-      end
-      sum *= -2.0
-    else # k != j
-      sum = 2.0 * win_rate(j,k) * win_rate(k,j) * (@n[k,j] + @n[j,k])
-    end
-    sum
-  end
-
-  ##
-  # Jacobi matrix of the func().
-  #   m00 m01
-  #   m10 m11
-  #
-  def j_matrix
-    GSL::Matrix[*
-      (0...@size).collect do |k|
-        (0...@size).collect do |j|
-          d_func(k,j)
-        end
-      end
-    ]
-  end
-
-  ##
-  # The initial value of the rate, which is of very importance for Newton
-  # method.  This is based on my huristics; the higher the win probablity of
-  # a player is, the greater points he takes.
-  #
-  def initial_rate
-    possibility = 
-      player_vector do |k|
-        v = GSL::Vector[0, 0]
-        each_player do |i|
-          next if k == i
-          v += GSL::Vector[@n[k,i], @n[i,k]]
-        end
-        v.nrm2 < 1 ? 0 : v[0] / (v[0] + v[1])
-      end
-    rank = possibility.sort_index
-    @rate = player_vector do |k|
-      K*500 * (rank[k]+1) / @size
-    end
-    average!
-  end
-
-  ##
-  # Resets @rate as the higher the current win probablity of a player is, 
-  # the greater points he takes. 
-  #
-  def initial_rate2
-    @rate = @record.get || @rate
-    rank = @rate.sort_index
-    @rate = player_vector do |k|
-      K*@count*1.5 * (rank[k]+1) / @size
-    end
-    average!
-  end
-
-  # mu is the deaccelrating parameter in Deaccelerated Newton method
-  def deaccelrate(mu, old_rate, a, old_f_nrm2)
-    @rate = old_rate - a * mu
-    if func_vector.nrm2 < (1 - mu / 4.0 ) * old_f_nrm2 then
-      return
-    end
-    if mu < 1e-4
-      @record.set(func_vector.nrm2, @rate)
-      initial_rate2
-      return
-    end
-    $stderr.puts "mu: %f " % [mu] if $DEBUG
-    deaccelrate(mu*0.5, old_rate, a, old_f_nrm2)
-  end
-
-  ##
-  # Main process to calculate ratings.
-  #
-  def rating
-    # Counter to stop the process. 
-    # Calulation in Newton method may fall in an infinite loop
-    @count = 0
-
-    # Main loop
-    begin
-      # Solve the equation: 
-      #   J*a=f
-      #   @rate_(n+1) = @rate_(n) - a
-      #
-      # f.nrm2 should approach to zero.
-      f = func_vector
-      j = j_matrix
-
-      # $stderr.puts "j: %s" % [j.inspect] if $DEBUG
-      $stderr.puts "f: %s -> %f" % [f.to_a.inspect, f.nrm2] if $DEBUG
-
-      # GSL::Linalg::LU.solve or GSL::Linalg::HH.solve would be available instead.
-      #a = GSL::Linalg::HH.solve(j, f)
-      a, = GSL::MultiFit::linear(j, f)
-      a = self.class.average(a)
-      # $stderr.puts "a: %s -> %f" % [a.to_a.inspect, a.nrm2] if $DEBUG
-      
-      # Deaccelerated Newton method
-      # GSL::Vector object should be immutable.
-      old_rate   = @rate
-      old_f      = f
-      old_f_nrm2 = old_f.nrm2
-      deaccelrate(1.0, old_rate, a, old_f_nrm2)
-      @record.set(func_vector.nrm2, @rate)
-
-      $stderr.printf "|error| : %5.2e\n", a.nrm2 if $DEBUG
-
-      @count += 1
-      if @count > COUNT_MAX
-        $stderr.puts "Values seem to oscillate. Stopped the process."
-        $stderr.puts "f: %s -> %f" % [func_vector.to_a.inspect, func_vector.nrm2]
-        break
-      end
-
-    end while (a.nrm2 > ERROR_LIMIT * @rate.nrm2)
-    
-    @rate = @record.get
-    $stderr.puts "resolved f: %s -> %f" %
-      [func_vector.to_a.inspect, func_vector.nrm2] if $DEBUG
-
-    @rate *= 1.0/K
-    finite!
-    self
-  end
-
-  ##
-  # Make the values of @rate finite.
-  #
-  def finite!
-    @rate = @rate.collect do |a|
-      if a.infinite?
-        a.infinite? * AVERAGE_RATE * 100
-      else
-        a
-      end
-    end
-  end
-
-  ##
-  # Flatten the values of @rate.
-  #
-  def average!(mean=0.0)
-    @rate = self.class.average(@rate, mean)
-  end
-
-  ##
-  # Translate by value
-  #
-  def translate!(value)
-    @rate += value
-  end
-
-  ##
-  # Make the values of @rate integer.
-  #
-  def integer!
-    @rate = @rate.collect do |a|
-      if a.finite?
-        a.to_i
-      elsif a.nan?
-        0
-      elsif a.infinite?
-        a.infinite? * AVERAGE_RATE * 100
-      end
-    end
-  end
-end
-
-#################################################
-# Encapsulate a pair of keys and win loss matrix.
-#   - keys is an array of player IDs; [gps+123, foo+234, ...]
-#   - matrix holds games # where player i (row index) beats player j (column index).
-#     The row and column indexes match with the keys.
-#
-# This object should be immutable. If an internal state is being modified, a
-# new object is always returned.
-#
-class WinLossMatrix
-
-  ###############
-  # Class methods
-  #  
-
-  def self.mk_matrix(players)
-    keys = players.keys.sort
-    size = keys.size
-    matrix =
-      GSL::Matrix[*
-      ((0...size).collect do |k|
-        p1 = keys[k]
-        p1_hash = players[p1]
-        ((0...size).collect do |j|
-          if k == j
-            0
-          else
-            p2 = keys[j]
-            v = p1_hash[p2] || Vector[0,0]
-            v[0]
-          end
-        end)
-      end)]
-    return WinLossMatrix.new(keys, matrix)
-  end
-
-  def self.mk_win_loss_matrix(players)
-    obj = mk_matrix(players)
-    return obj.filter
-  end
-
-  ##################
-  # Instance methods
-  #
-
-  # an array of player IDs; [gps+123, foo+234, ...]
-  attr_reader :keys
-
-  # matrix holds games # where player i (row index) beats player j (column index).
-  # The row and column indexes match with the keys.
-  attr_reader :matrix
-
-  def initialize(keys, matrix)
-    @keys   = keys
-    @matrix = matrix
-  end
-
-  ##
-  # Returns the size of the keys/matrix
-  #
-  def size
-    if @keys
-      @keys.size
-    else
-      nil
-    end
-  end
-
-  ##
-  # Removes players in a rows such as [1,3,5], and then returns a new
-  # object.
-  #
-  def delete_rows(rows)
-    rows = rows.sort.reverse
-
-    copied_cols = []
-    (0...size).each do |i|
-      next if rows.include?(i)
-      row = @matrix.row(i).clone
-      rows.each do |j|
-        row.delete_at(j)
-      end
-      copied_cols << row
-    end
-    if copied_cols.size == 0
-      new_matrix = GSL::Matrix.new
-    else
-      new_matrix = GSL::Matrix[*copied_cols]
-    end
-
-    new_keys = @keys.clone
-    rows.each do |j|
-      new_keys.delete_at(j)
-    end
-
-    return WinLossMatrix.new(new_keys, new_matrix)
-  end
-
-  ##
-  # Removes players who do not pass a criteria to be rated, and returns a
-  # new object.
-  # 
-  def filter
-    $stderr.puts @keys.inspect if $DEBUG
-    $stderr.puts @matrix.inspect if $DEBUG
-    delete = []  
-    (0...size).each do |i|
-      row = @matrix.row(i)
-      col = @matrix.col(i)
-      win  = row.sum
-      loss = col.sum
-      if win < 1 || loss < 1 || win + loss < $GAMES_LIMIT
-        delete << i
-      end
-    end
-
-    # The recursion ends if there is nothing to delete
-    return self if delete.empty?
-
-    new_obj = delete_rows(delete)
-    new_obj.filter
-  end
-
-  ##
-  # Cuts self into connecting groups such as each player in a group has at least
-  # one game with other players in the group. Returns them as an array.
-  #
-  def connected_subsets
-    g = RGL::AdjacencyGraph.new
-    (0...size).each do |k|
-      (0...size).each do |i|
-        next if k == i
-        if @matrix[k,i] > 0
-          g.add_edge(k,i)
-        end
-      end
-    end
-
-    subsets = []
-    g.each_connected_component do |c|
-      new_keys = []      
-      c.each do |v|
-        new_keys << keys[v.to_s.to_i]
-      end
-      subsets << new_keys
-    end
-
-    subsets = subsets.sort {|a,b| b.size <=> a.size}
-
-    result = subsets.collect do |keys|
-      matrix =
-        GSL::Matrix[*
-        ((0...keys.size).collect do |k|
-          p1 = @keys.index(keys[k])
-          ((0...keys.size).collect do |j|
-            if k == j
-              0
-            else
-              p2 = @keys.index(keys[j])
-              @matrix[p1,p2]
-            end
-          end)
-        end)]
-      WinLossMatrix.new(keys, matrix)
-    end
-
-    return result
-  end
-
-  def to_s
-    "size : #{@keys.size}" + "\n" +
-    @keys.inspect + "\n" + 
-    @matrix.inspect
-  end
-
-end
-
-
-#################################################
-# Main methods
-#
-
-# Half-life effect
-# After NHAFE_LIFE days value will get half.
-# 0.693 is constant, where exp(0.693) ~ 0.5
-def half_life(days)
-  if days < $options["half-life-ignore"]
-    return 1.0
-  else
-    Math::exp(-0.693/$options["half-life"]*(days-$options["half-life-ignore"]))
-  end
-end
-
-def _add_win_loss(winner, loser, time)
-  how_long_days = (Time.now - time)/(3600*24)
-  $players[winner] ||= Hash.new { GSL::Vector[0,0] }
-  $players[loser]  ||= Hash.new { GSL::Vector[0,0] }
-  $players[winner][loser] += GSL::Vector[1.0*half_life(how_long_days),0]
-  $players[loser][winner] += GSL::Vector[0,1.0*half_life(how_long_days)]
-end
-
-def _add_time(player, time)
-  $players_time[player] = time if $players_time[player] < time
-end
-
-def add(black_mark, black_name, white_name, white_mark, time)
-  if black_mark == WIN_MARK && white_mark == LOSS_MARK
-    _add_win_loss(black_name, white_name, time)
-  elsif black_mark == LOSS_MARK && white_mark == WIN_MARK
-    _add_win_loss(white_name, black_name, time)
-  elsif black_mark == DRAW_MARK && white_mark == DRAW_MARK
-    return
-  else
-    raise "Never reached!"
-  end
-  _add_time(black_name, time)
-  _add_time(white_name, time)
-end
-
-def identify_id(id)
-  if /@NORATE\+/ =~ id # the player having @NORATE in the name should not be rated
-    return nil
-  end
-  id.gsub(/@.*?\+/,"+")
-end
-
-def grep(file)
-  str = File.open(file).read
-
-  if /^N\+(.*)$/ =~ str then black_name = $1.strip end
-  if /^N\-(.*)$/ =~ str then white_name = $1.strip end
-
-  if /^'summary:(.*)$/ =~ str
-    state, p1, p2 = $1.split(":").map {|a| a.strip}    
-    return if state == "abnormal"
-    p1_name, p1_mark = p1.split(" ")
-    p2_name, p2_mark = p2.split(" ")
-    if p1_name == black_name
-      black_name, black_mark = p1_name, p1_mark
-      white_name, white_mark = p2_name, p2_mark
-    elsif p2_name == black_name
-      black_name, black_mark = p2_name, p2_mark
-      white_name, white_mark = p1_name, p1_mark
-    else
-      raise "Never reach!: #{black} #{white} #{p3} #{p2}"
-    end
-  end
-  if /^'\$END_TIME:(.*)$/ =~ str
-    time = Time.parse($1.strip)
-  end
-  if /^'rating:(.*)$/ =~ str
-    black_id, white_id = $1.split(":").map {|a| a.strip}
-    black_id = identify_id(black_id)
-    white_id = identify_id(white_id)
-    if black_id && white_id && (black_id != white_id) &&
-       black_mark && white_mark
-      $stdout.printf("%s %s %s %s %d\n", black_mark, black_id, white_id, white_mark, time)
-      $stdout.flush
-    end
-  end
-end
-
-def usage
-  $stderr.puts <<-EOF
-USAGE: #{$0} dir [...]
-  EOF
-  exit 1
-end
-
-def validate(yaml)
-  yaml["players"].each do |group_key, group|
-    group.each do |player_key, player|
-      rate = player['rate']
-      next unless rate
-      if rate > 10000 || rate < -10000
-        return false
-      end
-    end
-  end
-  return true
-end
-
-def usage(io)
-    io.puts <<EOF
-USAGE: #{$0} [options] DIR..
-  DIR                where CSA files are looked up recursively
-OPTOINS:
-  --half-life         n [days] (default 60)
-  --half-life-ignore  m [days] (default  7)
-                      after m days, half-life effect works
-  --fixed-rate-player player whose rate is fixed at the rate
-  --fixed-rate        rate 
-  --help              show this message
-EOF
-end
-
-def main
-  $options = Hash::new
-  parser = GetoptLong.new(
-    ["--half-life",         GetoptLong::REQUIRED_ARGUMENT],
-    ["--half-life-ignore",  GetoptLong::REQUIRED_ARGUMENT],
-    ["--help", "-h",        GetoptLong::NO_ARGUMENT],
-    ["--fixed-rate-player", GetoptLong::REQUIRED_ARGUMENT],
-    ["--fixed-rate",        GetoptLong::REQUIRED_ARGUMENT])
-  parser.quiet = true
-  begin
-    parser.each_option do |name, arg|
-      name.sub!(/^--/, '')
-      $options[name] = arg.dup
-    end
-    if ( $options["fixed-rate-player"] && !$options["fixed-rate"]) ||
-       (!$options["fixed-rate-player"] &&  $options["fixed-rate"]) ||
-       ( $options["fixed-rate-player"] &&  $options["fixed-rate"].to_i <= 0) 
-      usage($stderr)
-      exit 1
-    end
-  rescue
-    usage($stderr)
-    raise parser.error_message
-  end
-  if $options["help"]
-    usage($stdout) 
-    exit 0
-  end
-  $options["half-life"] ||= 60
-  $options["half-life"] = $options["half-life"].to_i
-  $options["half-life-ignore"] ||= 7
-  $options["half-life-ignore"] = $options["half-life-ignore"].to_i
-  $options["fixed-rate"] = $options["fixed-rate"].to_i if $options["fixed-rate"]
-
-  if ARGV.empty?
-    while line = $stdin.gets do
-      next unless %r!.*\.csa$! =~ line
-      grep line.strip
-    end
-  else
-    while dir = ARGV.shift do
-      Dir.glob( File.join(dir, "**", "*.csa") ) {|f| grep(f)}
-    end
-  end
-  $stderr.puts "read done."
-end
-
-if __FILE__ == $0
-  main
-end
-
-# vim: ts=2 sw=2 sts=0
index 72bcd66..33a2d70 100755 (executable)
@@ -1,4 +1,4 @@
-#! /usr/bin/env ruby
+#! /usr/bin/ruby1.9.1
 # $Id$
 #
 # Author:: NABEYA Kenichi, Daigo Moriwaki
@@ -6,7 +6,7 @@
 #
 #--
 # Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-# Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+# Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ $topdir = nil
 $league = nil
 $logger = nil
 $config = nil
-$:.unshift File.dirname(__FILE__)
+$:.unshift(File.dirname(File.expand_path(__FILE__)))
 require 'shogi_server'
 require 'shogi_server/config'
 require 'shogi_server/util'
@@ -138,6 +138,20 @@ FLOODGATE SCHEDULE CONFIGURATIONS
                Sat 22:00
                Sun 13:00
 
+            PAREMETER SETTING
+
+            In addition, this configuration file allows to set parameters
+            for the specific Floodaget group. A list of parameters is the
+            following:
+
+            * pairing_factory:
+              Specifies a factory function name generating a pairing
+              method which will be used in a specific Floodgate game.
+              ex. set pairing_factory floodgate_zyunisen
+            * sacrifice:
+              Specifies a sacrificed player.
+              ex. set sacrifice gps500+e293220e3f8a3e59f79f6b0efffaa931
+
 LICENSE
         GPL versoin 2 or later
 
@@ -372,6 +386,7 @@ def main
   $league.dir = $topdir
 
   config = {}
+  config[:BindAddress] = "0.0.0.0"
   config[:Port]       = port
   config[:ServerType] = WEBrick::Daemon if $options["daemon"]
   config[:Logger]     = $logger
@@ -417,7 +432,10 @@ def main
       client.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
         # Keepalive time can be set by /proc/sys/net/ipv4/tcp_keepalive_time
       player, login = login_loop(client) # loop
-      next unless player
+      unless player
+        log_error("Detected a timed out login attempt")
+        next
+      end
 
       log_message(sprintf("user %s login", player.name))
       login.process
@@ -428,12 +446,13 @@ def main
         if (player.game)
           player.game.kill(player)
         end
-        player.finish # socket has been closed
+        player.finish
         $league.delete(player)
         log_message(sprintf("user %s logout", player.name))
       ensure
         $mutex.unlock
       end
+      player.wait_write_thread_finish(1000) # milliseconds
     rescue Exception => ex
       log_error("server.start: #{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}")
     end
diff --git a/shogi-server-profile b/shogi-server-profile
new file mode 100755 (executable)
index 0000000..6f024c9
--- /dev/null
@@ -0,0 +1,74 @@
+#! /usr/bin/ruby1.9.1
+# $Id$
+#
+# Author:: Daigo Moriwaki
+# Homepage:: http://sourceforge.jp/projects/shogi-server/
+#
+#--
+# Copyright (C) 2011-2012 Daigo Moriwaki (daigo at debian dot org)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#++
+#
+# == Synopsis
+#
+# shogi-server-profile is a wrapper of shogi-server to take profile, which
+# is only used by Shogi-server developers.
+# 
+#
+# == Usage
+#
+# Same as shogi-server.
+# 
+# == PREREQUIRE
+#
+# Sample Command lines that isntall prerequires will work on Debian.
+#
+# * {ruby-prof}[http://rubyforge.org/projects/ruby-prof/]
+#
+#   $ sudo gem1.9.1 install ruby-prof
+#
+# == Run
+#
+# Same as shogi-server. It will result in a profile log file (calltree.log),
+# which can be read by KCacheGrind.
+#
+
+require 'ruby-prof'
+load 'shogi-server'
+
+
+if ($0 == __FILE__)
+  STDOUT.sync = true
+  STDERR.sync = true
+  TCPSocket.do_not_reverse_lookup = true
+  Thread.abort_on_exception = $DEBUG ? true : false
+
+  begin
+    result = RubyProf.profile do
+      main
+    end
+    printer = RubyProf::CallTreePrinter.new(result)
+    f = File.open("calltree.log", "w")
+    printer.print(f, {})
+  rescue Exception => ex
+    if $logger
+      log_error("main: #{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}")
+    else
+      $stderr.puts "main: #{ex.class}: #{ex.message}\n\t#{ex.backtrace[0]}"
+    end
+  end
+end
+
index 8bb2d6c..4ddf963 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -29,6 +29,7 @@ require 'webrick'
 require 'fileutils'
 require 'logger'
 
+require 'shogi_server/compatible'
 require 'shogi_server/board'
 require 'shogi_server/game'
 require 'shogi_server/league'
index c006176..3bd01b1 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -94,6 +94,7 @@ EOF
     @move_count = move_count
     @teban = nil # black => true, white => false
     @initial_moves = []
+    @ous = [nil, nil] # keep OU pieces of Sente and Gote
   end
   attr_accessor :array, :sente_hands, :gote_hands, :history, :sente_history, :gote_history, :teban
   attr_reader :move_count
@@ -153,6 +154,17 @@ EOF
     @teban = true
   end
 
+  # Cache OU piece.
+  # Piece#new will call back this method.
+  #
+  def add_ou(ou)
+    if ou.sente
+      @ous[0] = ou
+    else
+      @ous[1] = ou
+    end
+  end
+
   # Set up a board with the strs.
   # Failing to parse the moves raises an StandardError.
   # @param strs a board text
@@ -356,22 +368,13 @@ EOF
   end
   
   # def each_reserved_square
-
+  
   def look_for_ou(sente)
-    x = 1
-    while (x <= 9)
-      y = 1
-      while (y <= 9)
-        if (@array[x][y] &&
-            (@array[x][y].name == "OU") &&
-            (@array[x][y].sente == sente))
-          return @array[x][y]
-        end
-        y = y + 1
-      end
-      x = x + 1
+    if sente
+      return @ous[0]
+    else
+      return @ous[1]
     end
-    raise "can't find ou"
   end
 
   # See if sente is checked (i.e. loosing) or not.
index 8a2b38c..b09b95a 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -831,6 +831,7 @@ module ShogiServer
         @player.write_safe("##[GETBUOYCOUNT] %s\n" % [buoy_game.count])
       end
       @player.write_safe("##[GETBUOYCOUNT] +OK\n")
+      return :continue
     end
   end
 
diff --git a/shogi_server/compatible.rb b/shogi_server/compatible.rb
new file mode 100644 (file)
index 0000000..1cfd53c
--- /dev/null
@@ -0,0 +1,26 @@
+## $Id$
+
+## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+# Allow Ruby 1.8.7 to use Array#sample 
+# 
+unless ::Array.method_defined?(:sample)
+  class Array
+    alias_method :sample, :choice
+  end
+end
index 288a00e..1fd0d90 100644 (file)
@@ -1,6 +1,6 @@
 #--
 # Copyright (c) 2006-2009 by Craig P Jolicoeur <cpjolicoeur at gmail dot com>
-# Copyright (C) 2009 Daigo Moriwaki <daigo at debian dot org>
+# Copyright (C) 2009-2012 Daigo Moriwaki <daigo at debian dot org>
 # 
 # Permission is hereby granted, free of charge, to any person obtaining
 # a copy of this software and associated documentation files (the
index fb7ed18..ec9b702 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 291aa3d..a90289d 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 7b53486..dc02221 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 1207472..b3e9c46 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index b7f26f5..5d6ccaa 100644 (file)
@@ -27,11 +27,16 @@ class League
     #
     attr_reader :next_time
     attr_reader :league, :game_name
+    attr_reader :pairing_factory
+    attr_reader :options
 
     def initialize(league, hash={})
       @league = league
       @next_time = hash[:next_time] || nil
       @game_name = hash[:game_name] || "floodgate-900-0"
+      @pairing_factory = "default_factory" # will be updated by NextTimeGenerator
+      # Options will be updated by NextTimeGenerator
+      @options = {:sacrifice => "gps500+e293220e3f8a3e59f79f6b0efffaa931"}
       charge if @next_time.nil?
     end
 
@@ -41,6 +46,8 @@ class League
 
     def charge
       ntg = NextTimeGenerator.factory(@game_name)
+      @pairing_factory = ntg.pairing_factory
+      @options[:sacrifice] = ntg.sacrifice
       if ntg
         @next_time = ntg.call(Time.now)
       else
@@ -49,12 +56,14 @@ class League
     end
 
     def match_game
+      log_message("Starting Floodgate games...: %s, %s" % [@game_name, @pairing_factory])
       players = @league.find_all_players do |pl|
         pl.status == "game_waiting" &&
         game_name?(pl.game_name) &&
         pl.sente == nil
       end
-      Pairing.match(players)
+      logics = Pairing.send(@pairing_factory, @options)
+      Pairing.match(players, logics)
     end
     
     #
@@ -80,10 +89,24 @@ class League
       end
     end
 
+    class AbstructNextTimeGenerator
+
+      attr_reader :pairing_factory
+      attr_reader :sacrifice
+
+      # Constructor. 
+      #
+      def initialize
+        @pairing_factory = "default_factory"
+        @sacrifice       = "gps500+e293220e3f8a3e59f79f6b0efffaa931"
+      end
+    end
+
     # Schedule the next time from configuration files.
     #
     # Line format: 
     #   # This is a comment line
+    #   set <parameter_name> <value>
     #   DoW Time
     #   ...
     # where
@@ -97,12 +120,23 @@ class League
     #   Sat 22:00
     #   Sun 13:00
     #
-    class NextTimeGeneratorConfig
+    # Set parameters:
+    #
+    # * pairing_factory:
+    #   Specifies a factory function name generating a pairing
+    #   method which will be used in a specific Floodgate game.
+    #   ex. set pairing_factory floodgate_zyunisen
+    # * sacrifice:
+    #   Specifies a sacrificed player.
+    #   ex. set sacrifice gps500+e293220e3f8a3e59f79f6b0efffaa931
+    #
+    class NextTimeGeneratorConfig < AbstructNextTimeGenerator
       
       # Constructor. 
       # Read configuration contents.
       #
       def initialize(lines)
+        super()
         @lines = lines
       end
 
@@ -114,7 +148,12 @@ class League
         # now.cweek 1-53
         # now.cwday 1(Monday)-7
         @lines.each do |line|
-          if %r!^\s*(\w+)\s+(\d{1,2}):(\d{1,2})! =~ line
+          case line
+          when %r!^\s*set\s+pairing_factory\s+(\w+)!
+            @pairing_factory = $1
+          when %r!^\s*set\s+sacrifice\s+(.*)!
+            @sacrifice = $1
+          when %r!^\s*(\w+)\s+(\d{1,2}):(\d{1,2})!
             dow, hour, minute = $1, $2.to_i, $3.to_i
             dow_index = ::ShogiServer::parse_dow(dow)
             next if dow_index.nil?
@@ -123,6 +162,12 @@ class League
             time = DateTime::commercial(now.cwyear, now.cweek, dow_index, hour, minute) rescue next
             time += 7 if time <= now 
             candidates << time
+          when %r!^\s*#!
+            # Skip comment line
+          when %r!^\s*$!
+            # Skip empty line
+          else
+            log_warning("Floodgate: Unsupported syntax in a next time generator config file: %s" % [line]) 
           end
         end
         candidates.map! {|dt| ::ShogiServer::datetime2time(dt)}
@@ -132,7 +177,14 @@ class League
 
     # Schedule the next time for floodgate-900-0: each 30 minutes
     #
-    class NextTimeGenerator_Floodgate_900_0
+    class NextTimeGenerator_Floodgate_900_0 < AbstructNextTimeGenerator
+
+      # Constructor. 
+      #
+      def initialize
+        super
+      end
+
       def call(now)
         if now.min < 30
           return Time.mktime(now.year, now.month, now.day, now.hour, 30)
@@ -144,7 +196,14 @@ class League
 
     # Schedule the next time for floodgate-3600-0: each 2 hours (odd hour)
     #
-    class NextTimeGenerator_Floodgate_3600_0
+    class NextTimeGenerator_Floodgate_3600_0 < AbstructNextTimeGenerator
+
+      # Constructor. 
+      #
+      def initialize
+        super
+      end
+
       def call(now)
         return Time.mktime(now.year, now.month, now.day, now.hour) + ((now.hour%2)+1)*3600
       end
@@ -152,7 +211,14 @@ class League
 
     # Schedule the next time for debug: each 30 seconds.
     #
-    class NextTimeGenerator_Debug
+    class NextTimeGenerator_Debug < AbstructNextTimeGenerator
+
+      # Constructor. 
+      #
+      def initialize
+        super
+      end
+
       def call(now)
         if now.sec < 30
           return Time.mktime(now.year, now.month, now.day, now.hour, now.min, 30)
@@ -216,8 +282,13 @@ class League
       def load
         return unless @file.exist?
 
-        @records = YAML.load_file(@file)
-        unless @records && @records.instance_of?(Array)
+        begin
+          @records = YAML.load_file(@file)
+          unless @records && @records.instance_of?(Array)
+            $logger.error "%s is not a valid yaml file. Instead, an empty array will be used and updated." % [@file]
+            @records = []
+          end
+        rescue
           $logger.error "%s is not a valid yaml file. Instead, an empty array will be used and updated." % [@file]
           @records = []
         end
index 4cd9be1..231c8ce 100644 (file)
@@ -64,7 +64,6 @@ module ShogiServer
     end
 
     def start_games(floodgate)
-      log_message("Starting Floodgate games...: %s" % [floodgate.game_name])
       $league.reload
       floodgate.match_game
     end
@@ -74,6 +73,7 @@ module ShogiServer
     #
     def regenerate_leagues(next_array)
       leagues = next_array.collect do |game_name, next_time|
+        log_message("Regenerating a floodgate league...: %s %s" % [game_name, next_time])
         floodgate = ShogiServer::League::Floodgate.new($league, 
                                                        {:game_name => game_name,
                                                         :next_time => next_time})
index 1671abe..e176162 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 4cee31c..5af4398 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 8354e3c..ba4fe1e 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 8ad9336..946af2f 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -24,44 +24,52 @@ module ShogiServer
   class Pairing
 
     class << self
-      def default_factory
-        return least_diff_pairing
+      def default_factory(options)
+        return least_diff_pairing(options)
       end
 
-      def sort_by_rate_with_randomness
+      def sort_by_rate_with_randomness(options)
         return [LogPlayers.new,
-                ExcludeSacrificeGps500.new,
+                ExcludeSacrifice.new(options[:sacrifice]),
                 MakeEven.new,
                 SortByRateWithRandomness.new(1200, 2400),
                 StartGameWithoutHumans.new]
       end
 
-      def random_pairing
+      def random_pairing(options)
         return [LogPlayers.new,
-                ExcludeSacrificeGps500.new,
+                ExcludeSacrifice.new(options[:sacrifice]),
                 MakeEven.new,
                 Randomize.new,
                 StartGameWithoutHumans.new]
       end
 
-      def swiss_pairing
+      def swiss_pairing(options)
         return [LogPlayers.new,
-                ExcludeSacrificeGps500.new,
+                ExcludeSacrifice.new(options[:sacrifice]),
                 MakeEven.new,
                 Swiss.new,
                 StartGameWithoutHumans.new]
       end
 
-      def least_diff_pairing
+      def least_diff_pairing(options)
         return [LogPlayers.new,
-                ExcludeSacrificeGps500.new,
+                ExcludeSacrifice.new(options[:sacrifice]),
                 MakeEven.new,
                 LeastDiff.new,
                 StartGameWithoutHumans.new]
       end
 
-      def match(players)
-        logics = default_factory
+      def floodgate_zyunisen(options)
+        return [LogPlayers.new,
+                ExcludeUnratedPlayers.new,
+                ExcludeSacrifice.new(options[:sacrifice]),
+                MakeEven.new,
+                LeastDiff.new,
+                StartGameWithoutHumans.new]
+      end
+
+      def match(players, logics)
         logics.inject(players) do |result, item|
           item.match(result)
           result
@@ -136,7 +144,7 @@ module ShogiServer
     def match(players)
       super
       if players.size < 2
-        log_warning("Floodgate: There should be more than one player (%d)." % [players.size])
+        log_message("Floodgate: There are less than two players: %d" % [players.size])
         return
       end
       if players.size.odd?
@@ -159,7 +167,7 @@ module ShogiServer
       super
       log_players(players)
       if players.size < 2
-        log_warning("Floodgate: There should be more than one player (%d)." % [players.size])
+        log_message("Floodgate: There are less than two players: %d" % [players.size])
         return
       elsif players.size == 2
         start_game_shuffle(players)
@@ -298,7 +306,7 @@ module ShogiServer
     def match(players)
       super
       return if less_than_one?(players)
-      one = players.choice
+      one = players.sample
       log_message("Floodgate: Deleted %s at random" % [one.name])
       players.delete(one)
       log_players(players)
@@ -346,7 +354,7 @@ module ShogiServer
     # @sacrifice a player id to be eliminated
     def initialize(sacrifice)
       super()
-      @sacrifice = sacrifice
+      @sacrifice = sacrifice || "gps500+e293220e3f8a3e59f79f6b0efffaa931"
     end
 
     def match(players)
@@ -388,43 +396,74 @@ module ShogiServer
       players.shuffle
     end
 
-    # Returns a player's rate value.
+    # Update estimated rate of a player.
     # 1. If it has a valid rate, return the rate.
-    # 2. If it has no valid rate, return average of the following values:
-    #   a. For games it won, the opponent's rate + 100
-    #   b. For games it lost, the opponent's rate - 100
-    #   (if the opponent has no valid rate, count out the game)
-    #   (if there are not such games, return 2150 (default value)
+    # 2. If it has no valid rate, return:
+    #   a. If it won the last game, the opponent's rate + 200
+    #   b. If it lost the last game, the opponent's rate - 200
+    #   c. otherwise, return 2150 (default value)
     #
-    def get_player_rate(player, history)
-      return player.rate if player.rate != 0
-      return 2150 unless history
-
-      count = 0
-      sum = 0
-
-      history.win_games(player.player_id).each do |g|
-        next unless g[:loser]
-        name = g[:loser].split("+")[0]
-        p = $league.find(name)
-        if p && p.rate != 0
-          count += 1
-          sum += p.rate + 100
-        end
+    def estimate_rate(player, history)
+      player.estimated_rate = 2150 # default value
+
+      unless history
+        log_message("Floodgate: Without game history, estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
       end
-      history.loss_games(player.player_id).each do |g|
-        next unless g[:winner]
-        name = g[:winner].split("+")[0]
-        p = $league.find(name)
-        if p && p.rate != 0
-          count += 1
-          sum += p.rate - 100
-        end
+
+      g = history.last_valid_game(player.player_id)
+      unless g
+        log_message("Floodgate: Without any valid games in history, estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
+      end
+
+      opponent_id = nil
+      win         = true
+      case player.player_id
+      when g[:winner]
+        opponent_id = g[:loser]
+        win = true
+      when g[:loser]
+        opponent_id = g[:winner]
+        win = false
+      else
+        log_warning("Floodgate: The last valid game is invalid for %s!" % [player.name])
+        log_message("Floodgate: Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
+      end
+
+      opponent_name = opponent_id.split("+")[0]
+      p = $league.find(opponent_name)
+      unless p
+        log_message("Floodgate: No active opponent found. Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+        return
       end
 
-      estimate = (count == 0 ? 2150 : sum/count)
-      log_message("Floodgate: Estimated rate of %s is %d" % [player.name, estimate])
-      return estimate
+      opponent_rate = 0
+      if p.rate != 0
+        opponent_rate = p.rate
+      elsif p.estimated_rate != 0
+        opponent_rate = p.estimated_rate
+      end
+
+      if opponent_rate != 0
+        player.estimated_rate = opponent_rate + (win ? 200 : -200)
+      end
+
+      log_message("Floodgate: Estimated %s's rate: %d" % [player.name, player.estimated_rate])
+    end
+
+    # Return a player's rate based on its actual rate or estimated rate.
+    #
+    def get_player_rate(player, history)
+      if player.rate != 0
+        return player.rate
+      elsif player.estimated_rate != 0
+        return player.estimated_rate 
+      else
+        estimate_rate(player, history)
+        return player.estimated_rate
+      end
     end
 
     def calculate_diff_with_penalty(players, history)
@@ -467,6 +506,9 @@ module ShogiServer
         return players
       end
 
+      # Reset estimated rate
+      players.each {|p| p.estimated_rate = 0}
+
       # 10 trials
       matches = []
       scores  = []
@@ -493,10 +535,23 @@ module ShogiServer
           min_score = s
         end
       end
-      log_message("Floodgate: the least score %d (%d per player) [%s]" % [min_score, min_score/players.size, scores.join(" ")])
+      log_message("Floodgate: the least score %d (%d per game) [%s]" % [min_score, min_score/players.size*2, scores.join(" ")])
 
       players.replace(matches[min_index])
     end
   end
 
+  # This pairing method excludes unrated players
+  #
+  class ExcludeUnratedPlayers < Pairing
+
+    def match(players)
+      super
+
+      log_message("Floodgate: Deleting unrated players...")
+      players.delete_if{|a| a.rate == 0}
+      log_players(players)
+    end
+  end # class ExcludeUnratedPlayers
+
 end # ShogiServer
index 93d085f..64b918a 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -393,6 +393,7 @@ class PieceOU < Piece
     @name = "OU"
     @promoted_name = nil
     super
+    @board.add_ou(self)
   end
 end
 
index 7e235f9..471119b 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@ class BasicPlayer
     @name = nil
     @password = nil
     @rate = 0
+    @estimated_rate = 0
     @win  = 0
     @loss = 0
     @last_game_win = false
@@ -48,6 +49,10 @@ class BasicPlayer
   # Score in the rating sysem
   attr_accessor :rate
 
+  # Estimated rate for unrated player (rate == 0)
+  # But this value is not persisted and cleared when player logs off.
+  attr_accessor :estimated_rate
+
   # Number of games for win and loss in the rating system
   attr_accessor :win, :loss
   
@@ -118,8 +123,8 @@ class BasicPlayer
 
   def set_sente_from_str(str)
     case str
-    when "+": @sente = true
-    when "-": @sente = false
+    when "+" then @sente = true
+    when "-" then @sente = false
     else
       # str should be "*"
       @sente = nil
@@ -206,7 +211,6 @@ class Player < BasicPlayer
           write_safe(nil)
           Thread.pass # help the write_thread to terminate
         end
-        @player_logger.close if @player_logger
         log_debug("done.")
       rescue
         log_message(sprintf("user %s finish failed", @name))    
@@ -248,6 +252,17 @@ class Player < BasicPlayer
   end
 
   #
+  # Wait for the write thread to finish.
+  # This method should be called just before this instance will be freed.
+  #
+  def wait_write_thread_finish(msec=1000)
+    while msec > 0 && @write_thread && @write_thread.alive?
+      sleep 0.1; msec -= 0.1
+    end
+    @player_logger.close if @player_logger
+  end
+
+  #
   # Note that sending a message is included in the giant lock.
   #
   def write_safe(str)
@@ -307,6 +322,7 @@ class Player < BasicPlayer
           # do nothing
         else
           # TODO never reach
+          log_error("Detected a wrong return value for %s" % [cmd])
         end
 
       ensure
index adeacc4..758e5bf 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index 044bd2a..e1813d3 100644 (file)
@@ -1,7 +1,7 @@
 ## $Id$
 
 ## Copyright (C) 2004 NABEYA Kenichi (aka nanami@2ch)
-## Copyright (C) 2007-2008 Daigo Moriwaki (daigo at debian dot org)
+## Copyright (C) 2007-2012 Daigo Moriwaki (daigo at debian dot org)
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by
index ca66262..d82277d 100644 (file)
@@ -4,6 +4,7 @@ require 'TC_board'
 require 'TC_before_agree'
 require 'TC_buoy'
 require 'TC_command'
+require 'TC_compatible'
 require 'TC_config'
 require 'TC_floodgate'
 require 'TC_floodgate_history'
index 8a196e7..76cabe3 100644 (file)
@@ -1,4 +1,6 @@
-require "baseclient"
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 require "kconv"
 
 class TestBeforeAgree < BaseClient
@@ -7,6 +9,7 @@ class TestBeforeAgree < BaseClient
     login
 
     @p1.puts "AGREE"
+    sleep 0.1
     @p2.puts "LOGOUT"
     @p1.wait /^REJECT/
     @p2.wait /^REJECT/
@@ -17,6 +20,7 @@ class TestBeforeAgree < BaseClient
     login
 
     @p2.puts "AGREE"
+    sleep 0.1
     @p1.puts "LOGOUT"
     @p1.wait /^REJECT/
     @p2.wait /^REJECT/
@@ -26,6 +30,7 @@ class TestBeforeAgree < BaseClient
   def test_gote_logout_before_sente_agree
     login
 
+    sleep 0.1
     @p2.puts "LOGOUT"
     @p1.wait /^REJECT/
     @p2.wait /^REJECT/
@@ -35,6 +40,7 @@ class TestBeforeAgree < BaseClient
   def test_sente_logout_before_gote_agree
     login
 
+    sleep 0.1
     @p1.puts "LOGOUT"
     @p1.wait /^REJECT/
     @p2.wait /^REJECT/
index 1c15ca0..03a18d2 100644 (file)
@@ -2,9 +2,9 @@ $:.unshift File.join(File.dirname(__FILE__), "..")
 $topdir = File.expand_path File.dirname(__FILE__)
 require 'test/unit'
 require 'shogi_server/buoy'
-require 'mock_game'
-require 'mock_player'
-require 'mock_log_message'
+require 'test/mock_game'
+require 'test/mock_player'
+require 'test/mock_log_message'
 
 
 class TestBuoyGame < Test::Unit::TestCase
index 3cb3795..5e231fa 100644 (file)
@@ -2,8 +2,8 @@ $:.unshift File.join(File.dirname(__FILE__), "..")
 $topdir = File.expand_path File.dirname(__FILE__)
 require 'test/unit'
 require 'tempfile'
-require 'mock_game'
-require 'mock_log_message'
+require 'test/mock_game'
+require 'test/mock_log_message'
 require 'test/mock_player'
 require 'shogi_server/login'
 require 'shogi_server/player'
@@ -842,7 +842,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?("buoy_hoge-1500-0")
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_hoge-1500-0", "+7776FU", 2
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert !@buoy.is_new_game?("buoy_hoge-1500-0")
     assert !$p1.out.empty?
     assert !$p2.out.empty?
@@ -854,7 +854,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?("buoy_hoge-1500-0")
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_hoge-1500-0", "+7776FU", 1
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert @buoy.is_new_game?("buoy_hoge-1500-0")
     assert !$p1.out.empty?
     assert !$p2.out.empty?
@@ -864,7 +864,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?("buoy_hoge-1500-0")
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoyhoge-1500-0", "+7776FU", 1
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert @buoy.is_new_game?("buoy_hoge-1500-0")
@@ -878,7 +878,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_duplicated-1500-0", "+7776FU", 1
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert !@buoy.is_new_game?("buoy_duplicated-1500-0")
@@ -888,7 +888,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?("buoy_badmoves-1500-0")
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_badmoves-1500-0", "+7776FU+8786FU", 1
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert @buoy.is_new_game?("buoy_badmoves-1500-0")
@@ -898,7 +898,7 @@ class TestSetBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?("buoy_badcounter-1500-0")
     cmd = ShogiServer::SetBuoyCommand.new "%%SETBUOY", @p, "buoy_badcounter-1500-0", "+7776FU", 0
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert @buoy.is_new_game?("buoy_badcounter-1500-0")
@@ -916,7 +916,7 @@ class TestDeleteBuoyCommand < BaseTestBuoyCommand
     assert !@buoy.is_new_game?(buoy_game.game_name)
     cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert @buoy.is_new_game?(buoy_game.game_name)
@@ -927,7 +927,7 @@ class TestDeleteBuoyCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?(buoy_game.game_name)
     cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert $p1.out.empty?
     assert $p2.out.empty?
     assert @buoy.is_new_game?(buoy_game.game_name)
@@ -941,7 +941,7 @@ class TestDeleteBuoyCommand < BaseTestBuoyCommand
 
     cmd = ShogiServer::DeleteBuoyCommand.new "%%DELETEBUOY", @p, buoy_game.game_name
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert_equal "##[ERROR] you are not allowed to delete a buoy game that you did not set: buoy_anotherplayer-1500-0\n", @p.out.first
     assert !@buoy.is_new_game?(buoy_game.game_name)
   end
@@ -979,7 +979,7 @@ class TestGetBuoyCountCommand < BaseTestBuoyCommand
     assert !@buoy.is_new_game?(buoy_game.game_name)
     cmd = ShogiServer::GetBuoyCountCommand.new "%%GETBUOYCOUNT", @p, buoy_game.game_name
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert_equal ["##[GETBUOYCOUNT] 1\n", "##[GETBUOYCOUNT] +OK\n"], @p.out
   end
 
@@ -988,7 +988,7 @@ class TestGetBuoyCountCommand < BaseTestBuoyCommand
     assert @buoy.is_new_game?(buoy_game.game_name)
     cmd = ShogiServer::GetBuoyCountCommand.new "%%GETBUOYCOUNT", @p, buoy_game.game_name
     rt = cmd.call
-    assert :continue, rt
+    assert_equal :continue, rt
     assert_equal ["##[GETBUOYCOUNT] -1\n", "##[GETBUOYCOUNT] +OK\n"], @p.out
   end
 end
diff --git a/test/TC_compatible.rb b/test/TC_compatible.rb
new file mode 100644 (file)
index 0000000..6716d9b
--- /dev/null
@@ -0,0 +1,11 @@
+$:.unshift File.join(File.dirname(__FILE__), "..")
+
+require 'test/unit'
+require 'shogi_server'
+require 'shogi_server/compatible'
+
+class TestCompatibleArray < Test::Unit::TestCase
+  def test_sample
+    assert [1,2].include?([1,2].sample)
+  end
+end
index de49da3..56e242e 100644 (file)
@@ -24,12 +24,12 @@ class TestFloodgate < Test::Unit::TestCase
   end
 
   def test_instance_game_name
-    fg = ShogiServer::League::Floodgate.new(nil, "floodgate-900-0")
-    assert(fg.game_name?("floodgate-900-0"))
-    assert(!fg.game_name?("floodgate-3600-0"))
-    fg = ShogiServer::League::Floodgate.new(nil, "floodgate-3600-0")
+    fg = ShogiServer::League::Floodgate.new(nil, {:game_name => "floodgate-900-0"})
     assert(fg.game_name?("floodgate-900-0"))
     assert(!fg.game_name?("floodgate-3600-0"))
+    fg = ShogiServer::League::Floodgate.new(nil, {:game_name => "floodgate-3600-0"})
+    assert(!fg.game_name?("floodgate-900-0"))
+    assert(fg.game_name?("floodgate-3600-0"))
   end
 
 end
@@ -88,7 +88,8 @@ class TestMakeEven < Test::Unit::TestCase
  def test_match_odd
     players = [@a, @b, @c]
     @pairing.match(players)
-    assert_equal([@a, @b], players)
+    assert_equal(2, players.size)
+    assert(players[0] != players[1])
   end
 end
 
@@ -137,7 +138,10 @@ class TestRandomize < Test::Unit::TestCase
   def test_match
     players = [@a, @b, @c]
     @pairing.match(players)
-    assert_equal([@b,@a,@c], players)
+    assert_equal(3, players.size)
+    assert(players.include? @a)
+    assert(players.include? @b)
+    assert(players.include? @c)
   end
 end
 
index 4667088..f8761b8 100644 (file)
@@ -5,6 +5,9 @@ require 'shogi_server'
 require 'shogi_server/player'
 require 'shogi_server/league/floodgate'
 
+$league = ShogiServer::League.new(File.dirname(__FILE__))
+$league.event = "TC_floodgate_history"
+
 class MockGame
   attr_accessor :game_id, :game_name
 
index a52c6c2..297d63b 100644 (file)
@@ -2,7 +2,8 @@ $:.unshift File.join(File.dirname(__FILE__), "..")
 require 'test/unit'
 require 'shogi_server'
 require 'shogi_server/league/floodgate'
-require 'ftools'
+require 'fileutils'
+require 'test/mock_log_message'
 
 $topdir = File.expand_path File.dirname(__FILE__)
 
@@ -142,24 +143,38 @@ class TestNextTimeGeneratorConfig < Test::Unit::TestCase
   def setup
   end
 
+  def test_comment
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(#\ comment1 Thu\ 22:00 #\ comment2)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+  end
+
+  def test_empty_line
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(\  Thu\ 22:00 \  hoge)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+  end
+
   def test_read
     now = DateTime.new(2010, 6, 10, 21, 20, 15) # Thu
     assert_equal DateTime.parse("10-06-2010 21:20:15"), now
 
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 22:00"]
     assert_instance_of Time, ntc.call(now)
     assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 22:15"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 22:15"]
     assert_equal Time.parse("10-06-2010 22:15"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Fri 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Fri 22:00"]
     assert_equal Time.parse("11-06-2010 22:00"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Sat 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Sat 22:00"]
     assert_equal Time.parse("12-06-2010 22:00"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Sun 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Sun 22:00"]
     assert_equal Time.parse("13-06-2010 22:00"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Mon 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Mon 22:00"]
     assert_equal Time.parse("14-06-2010 22:00"), ntc.call(now)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 20:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 20:00"]
     assert_equal Time.parse("17-06-2010 20:00"), ntc.call(now)
   end
 
@@ -189,17 +204,49 @@ class TestNextTimeGeneratorConfig < Test::Unit::TestCase
 
   def test_read_time
     now = Time.mktime(2010, 6, 10, 21, 20, 15)
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 22:00"]
     assert_instance_of Time, ntc.call(now)
   end
 
   def test_read_change
     now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 22:00"]
     assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
 
     now = DateTime.new(2010, 6, 10, 22, 0, 0) # Thu
-    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new "Thu 22:00"
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new ["Thu 22:00"]
     assert_equal Time.parse("17-06-2010 22:00"), ntc.call(now)
   end
+
+  def test_default_pairing_factory
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(Thu\ 22:00)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+    assert_equal("default_factory", ntc.pairing_factory)
+  end
+
+  def test_read_pairing_factory
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(set\ pairing_factory\ least_diff_pairing Thu\ 22:00)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+    assert_equal("least_diff_pairing", ntc.pairing_factory)
+  end
+
+  def test_default_sacrifice
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(Thu\ 22:00)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+    assert_equal("gps500+e293220e3f8a3e59f79f6b0efffaa931", ntc.sacrifice)
+  end
+
+  def test_read_sacrifice
+    now = DateTime.new(2010, 6, 10, 21, 59, 59) # Thu
+    lines = %w(set\ sacrifice\ yowai_gps+95908f6c18338f5340371f71523fc5e3 Thu\ 22:00)
+    ntc = ShogiServer::League::Floodgate::NextTimeGeneratorConfig.new lines
+    assert_equal Time.parse("10-06-2010 22:00"), ntc.call(now)
+    assert_equal("yowai_gps+95908f6c18338f5340371f71523fc5e3", ntc.sacrifice)
+  end
 end
index fdf0d0b..51aca58 100644 (file)
@@ -1,4 +1,7 @@
-require "baseclient"
+# -*- coding: windows-31j -*-
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 require "kconv"
 
 class TestClientAtmark < BaseClient
index 824cafc..2d5242d 100644 (file)
@@ -1,4 +1,6 @@
-require "baseclient"
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 include Socket::Constants
 
 class JishogiTest < ReadFileClient
index a50b034..5b4f971 100644 (file)
@@ -40,7 +40,7 @@ class TestPersistent < Test::Unit::TestCase
 
     assert_equal(p.name, "gps_normal")
     assert_in_delta(p.rate, -1752.0, 0.1)
-    assert_equal(p.modified_at.to_s, "Thu May 08 23:50:54 +0900 2008")
+    assert_equal(p.modified_at.ctime, "Thu May  8 23:50:54 2008")
     assert_equal(p.rating_group, 0)
     assert_in_delta(p.win, 3384.04877829976,  0.00001)
     assert_in_delta(p.loss, 906.949084230512, 0.00001)
index 48db046..39021c4 100644 (file)
@@ -8,10 +8,10 @@ class TestMove < Test::Unit::TestCase
 
   def test_is_drop
     m = ShogiServer::Move.new 6,7,8,9,"FU",true
-    assert 6, m.x0
-    assert 7, m.y0
-    assert 8, m.x1
-    assert 9, m.y1
+    assert 6, m.x0.to_s
+    assert 7, m.y0.to_s
+    assert 8, m.x1.to_s
+    assert 9, m.y1.to_s
     assert_equal "FU", m.name
     assert m.sente
 
index 9a39d97..7548bc4 100644 (file)
@@ -1,4 +1,6 @@
-require "baseclient"
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 include Socket::Constants
 
 class NotSennichiteTest < ReadFileClient
index 926ef78..631b18c 100644 (file)
@@ -1,4 +1,6 @@
-require "baseclient"
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 include Socket::Constants
 
 class OuteSennichiteTest < ReadFileClient
index 90cea15..30f353e 100644 (file)
@@ -551,6 +551,7 @@ class TestLeastDiff < Test::Unit::TestCase
   def test_get_player_rate_0
     assert_equal(2150, @pairing.get_player_rate(@x, @history))
 
+    @x.estimated_rate = 0
     dummy = nil
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-a-1", 
@@ -558,8 +559,9 @@ class TestLeastDiff < Test::Unit::TestCase
        :winner => "x", :loser => "a"}
     end
     @history.update(dummy)
-    assert_equal(@a.rate+100, @pairing.get_player_rate(@x, @history))
+    assert_equal(@a.rate+200, @pairing.get_player_rate(@x, @history))
 
+    @x.estimated_rate = 0
     def @history.make_record(game_result)
       {:game_id => "wdoor+floodgate-900-0-x-b-1", 
        :black => "x",  :white => "b",
@@ -567,7 +569,62 @@ class TestLeastDiff < Test::Unit::TestCase
     end
     @history.update(dummy)
 
-    assert_equal((@a.rate+100+@b.rate-100)/2, @pairing.get_player_rate(@x, @history))
+    assert_equal(@b.rate-200, @pairing.get_player_rate(@x, @history))
   end
 end
 
+class TestExcludeUnratedPlayers < Test::Unit::TestCase
+  def setup
+    @pairing= ShogiServer::ExcludeUnratedPlayers.new
+    @a = ShogiServer::BasicPlayer.new
+    @a.name = "a"
+    @a.win  = 1
+    @a.loss = 2
+    @a.rate = 0
+    @b = ShogiServer::BasicPlayer.new
+    @b.name = "b"
+    @b.win  = 10
+    @b.loss = 20
+    @b.rate = 1500
+    @c = ShogiServer::BasicPlayer.new
+    @c.name = "c"
+    @c.win  = 100
+    @c.loss = 200
+    @c.rate = 1000
+    @d = ShogiServer::BasicPlayer.new
+    @d.name = "d"
+    @d.win  = 1000
+    @d.loss = 2000
+    @d.rate = 2000
+  end
+
+  def test_match_without_any_players
+    players = []
+    @pairing.match(players)
+    assert_equal([], players)
+  end
+
+  def test_match_without_unrated_player_1
+    players = [@b, @c, @d]
+    @pairing.match(players)
+    assert_equal([@b, @c, @d], players)
+  end
+
+  def test_match_without_unrated_player_2
+    players = [@b]
+    @pairing.match(players)
+    assert_equal([@b], players)
+  end
+
+  def test_match_with_unrated_player_1
+    players = [@a, @b, @c, @d]
+    @pairing.match(players)
+    assert_equal([@b, @c, @d], players)
+  end
+
+  def test_match_with_unrated_player_2
+    players = [@a]
+    @pairing.match(players)
+    assert_equal([], players)
+  end
+end
index 16ba282..c84ddea 100644 (file)
@@ -1,9 +1,11 @@
-require "baseclient"
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
 include Socket::Constants
 
 class UchifuzumeTest < ReadFileClient
   def test_uchifuzume
-    csa = File.open(filepath("uchifuzume.csa"){|f| f.read}
+    csa = File.open(filepath("uchifuzume.csa"), "r+:shift_jis"){|f| f.read}
     handshake(csa)
     @p2.puts "-0064FU"
     @p1.puts "%TORYO"
@@ -14,7 +16,7 @@ class UchifuzumeTest < ReadFileClient
   end
 
   def test_not_uchifuzume
-    csa = File.open(filepath("not_uchifuzume.csa"){|f| f.read}
+    csa = File.open(filepath("not_uchifuzume.csa"), "r+:shift_jis"){|f| f.read}
     handshake(csa)
     @p2.puts "-0092FU"
     @p1.puts "%TORYO"
index 2d3be05..28539d7 100644 (file)
@@ -1,14 +1,18 @@
 #!/usr/bin/ruby
 
+require 'logger'
 require 'socket'
 require 'thread'
 
+$logger = nil
+
 class BenchPlayer
   def initialize(game_name, name, sente)
     @game_name = game_name
     @name = "%s_%s" % [game_name, name]
     @turn_mark = sente ? "+" : "-"
     @nmoves = 0
+    @socket = nil
   end
   attr_reader :nmoves
 
@@ -22,37 +26,42 @@ class BenchPlayer
 
   def reader
     Thread.new do
+      Thread.pass
       loop do 
-        if r = select([@socket], nil, nil, 10)
+        if r = select([@socket], nil, nil, 300)
           str = r[0].first.gets
           if %r!^[\+\-]\d{4}\w{2},T\d+$! =~ str
             @nmoves += 1
           end
-          @message << str
+          @message << str if str
         else
-          raise "timed out"
+          $logger.warn "Timed out: %s" % [@name]
         end
       end
+      $logger.error "Socket error: %s" % [@name]
     end
   end
 
   def wait(reg)
     loop do 
       break if reg =~ @message
-      sleep 0.1
+      #$logger.debug "WAIT %s: %s" % [reg, @message]
+      sleep 0.001
+      #Thread.pass
     end
   end
 
   def wait_nmoves(n)
     loop do
       break if @nmoves == n
-      sleep 0.01
+      sleep 0.001
+      #Thread.pass
     end
   end
 
   def login
     @socket.puts "LOGIN #{@name} dummy x1"
-    wait %r!^LOGIN!
+    wait %r!^##\[LOGIN\] \+OK!
   end
 
   def game
@@ -94,12 +103,20 @@ class BenchGame
   end
 
   def start
+    $logger.info "Starting... %s" % [@game_name]
+    $logger.debug "Connecting... %s" % [@game_name]
     each_player {|player| player.connect}
+    $logger.debug "Logging in... %s" % [@game_name]
     each_player {|player| player.login}
+    $logger.debug "Sending GAME... %s" % [@game_name]
     each_player {|player| player.game}
+    $logger.debug "Waiting... %s" % [@game_name]
     each_player {|player| player.wait %r!^END Game_Summary!}
+    $logger.debug "Agreeing... %s" % [@game_name]
     each_player {|player| player.agree}
+    $logger.debug "AGREE waiting... %s" % [@game_name]
     each_player {|player| player.wait %r!^START:!}
+    $logger.info "Started %s" % [@game_name]
     turn = true # black
     nmoves = 0
     @csa.each_line do |line|
@@ -115,10 +132,15 @@ class BenchGame
         turn = true
         nmoves += 1
       when /^%TORYO/
+        $logger.debug "Waiting TORYO... %s" % [@game_name]
+        @p1.wait_nmoves nmoves
+        @p2.wait_nmoves nmoves
         turn ? @p1.toryo : @p2.toryo
       end
     end
+    $logger.info "Logging out... %s" % [@game_name]
     each_player {|player| player.logout}
+    $logger.info "Finished %s" % [@game_name]
   end
 end
 
@@ -127,11 +149,15 @@ if __FILE__ == $0
   filepath = ARGV.shift || File.join(File.dirname(__FILE__), "csa", "wdoor+floodgate-900-0+gps_normal+gps_l+20100507120007.csa")
   csa = File.open(filepath){|f| f.read} 
 
+  $logger = Logger.new(STDOUT)
+  $logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO  
+
   nclients = ARGV.shift || 1
   nclients = nclients.to_i
   threads = []
   nclients.times do |i|
     threads << Thread.new do
+      Thread.pass
       game = BenchGame.new("b#{i}", csa)
       game.start
     end
index 55319fd..fa20abf 100644 (file)
@@ -6,6 +6,7 @@ class MockPlayer < ShogiServer::BasicPlayer
   attr_accessor :game, :status, :protocol
   attr_accessor :game_name
   attr_reader :socket_buffer
+  attr_reader :rate
 
   def initialize
     @name     = "mock_player"
@@ -15,6 +16,7 @@ class MockPlayer < ShogiServer::BasicPlayer
     @protocol = nil
     @game_name = "dummy_game_name"
     @socket_buffer = []
+    @rate = 1500
   end
 
   def write_safe(str)
index 5df6167..9e3cbb2 100644 (file)
---- 
-players: 
-  5: 
-    gps2_k7p+5426a28d8a75cd7ed662b2090ca881c9: 
+---
+players:
+  5:
+    gps2_k7p+5426a28d8a75cd7ed662b2090ca881c9:
       name: gps2_k7p
       rate: 1051.0
       win: 11.8352784293642
       loss: 7.89360618372286
       rating_group: 5
-      last_modified: 2008-05-01 03:37:26 +09:00
-    gps2_rg+6a8be1bf7a75b6f75ee31f8c1c0c489a: 
+      last_modified: 2008-05-01 03:37:26.000000000 +09:00
+    gps2_rg+6a8be1bf7a75b6f75ee31f8c1c0c489a:
       name: gps2_rg
       rate: 1051.0
       win: 12.0
       loss: 8.0
       rating_group: 5
-      last_modified: 2008-05-04 12:19:51 +09:00
-    gps2_k7p4+e5f61cad57b66e6483b0ac3933564168: 
+      last_modified: 2008-05-04 12:19:51.000000000 +09:00
+    gps2_k7p4+e5f61cad57b66e6483b0ac3933564168:
       name: gps2_k7p4
       rate: 897.0
       win: 8.0
       loss: 13.0
       rating_group: 5
-      last_modified: 2008-05-03 08:03:56 +09:00
-    gps2_k7p3+2ee3afcc1fda4ce87023a575102da0b5: 
+      last_modified: 2008-05-03 08:03:56.000000000 +09:00
+    gps2_k7p3+2ee3afcc1fda4ce87023a575102da0b5:
       name: gps2_k7p3
       rate: 981.0
       win: 9.0
       loss: 9.0
       rating_group: 5
-      last_modified: 2008-05-02 15:35:04 +09:00
-    gps2_k7p2+fc2919b6df6578ce4b4a6a449fd73346: 
+      last_modified: 2008-05-02 15:35:04.000000000 +09:00
+    gps2_k7p2+fc2919b6df6578ce4b4a6a449fd73346:
       name: gps2_k7p2
       rate: 1036.0
       win: 10.9621929140671
       loss: 7.96664156541485
       rating_group: 5
-      last_modified: 2008-05-01 23:28:07 +09:00
-    gps2+2dd0aa2d841f508edc69bb113f70642b: 
+      last_modified: 2008-05-01 23:28:07.000000000 +09:00
+    gps2+2dd0aa2d841f508edc69bb113f70642b:
       name: gps2
       rate: 981.0
       win: 45.8602477491377
       loss: 51.7974713434314
       rating_group: 5
-      last_modified: 2008-05-04 12:19:51 +09:00
-  0: 
-    gps_pp+1e5a182134af18b0c64843196e2b4e81: 
+      last_modified: 2008-05-04 12:19:51.000000000 +09:00
+  0:
+    gps_pp+1e5a182134af18b0c64843196e2b4e81:
       name: gps_pp
       rate: 2866.0
       win: 19.0
       loss: 21.0
       rating_group: 0
-      last_modified: 2008-05-07 22:52:24 +09:00
-    gps_ppa2+6c5dc86d68f9130735e60b0fe9a2ea96: 
+      last_modified: 2008-05-07 22:52:24.000000000 +09:00
+    gps_ppa2+6c5dc86d68f9130735e60b0fe9a2ea96:
       name: gps_ppa2
       rate: 2840.0
       win: 13.9897623400963
       loss: 17.9879456013727
       rating_group: 0
-      last_modified: 2008-05-02 13:11:30 +09:00
-    gps_do2+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-05-02 13:11:30.000000000 +09:00
+    gps_do2+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_do2
       rate: 2912.0
       win: 53.986531798629
       loss: 45.9909614051652
       rating_group: 0
-      last_modified: 2008-05-03 20:38:24 +09:00
-    gps_normal+e293220e3f8a3e59f79f6b0efffaa931: 
+      last_modified: 2008-05-03 20:38:24.000000000 +09:00
+    gps_normal+e293220e3f8a3e59f79f6b0efffaa931:
       name: gps_normal
       rate: -1752.0
       win: 3384.04877829976
       loss: 906.949084230512
       rating_group: 0
-      last_modified: 2008-05-08 23:50:54 +09:00
-    gps_qtsee+d094a7c36b2c59d9cd7fcd2231505f8a: 
+      last_modified: 2008-05-08 23:50:54.000000000 +09:00
+    gps_qtsee+d094a7c36b2c59d9cd7fcd2231505f8a:
       name: gps_qtsee
       rate: 2991.0
       win: 18.9090769183675
       loss: 10.1784071014068
       rating_group: 0
-      last_modified: 2008-04-04 22:25:14 +09:00
-    gps_cc+503016c7f3e9d55687099f632e7b7dff: 
+      last_modified: 2008-04-04 22:25:14.000000000 +09:00
+    gps_cc+503016c7f3e9d55687099f632e7b7dff:
       name: gps_cc
       rate: 2802.0
       win: 9.23774550873844
       loss: 14.8077130398311
       rating_group: 0
-      last_modified: 2008-04-25 13:43:00 +09:00
-    gps_cc3+9aff337746cbc96eccaef09f45a17765: 
+      last_modified: 2008-04-25 13:43:00.000000000 +09:00
+    gps_cc3+9aff337746cbc96eccaef09f45a17765:
       name: gps_cc3
       rate: 2936.0
       win: 21.8292497973772
       loss: 16.1510769520277
       rating_group: 0
-      last_modified: 2008-04-28 00:53:35 +09:00
-    gps500+e293220e3f8a3e59f79f6b0efffaa931: 
+      last_modified: 2008-04-28 00:53:35.000000000 +09:00
+    gps500+e293220e3f8a3e59f79f6b0efffaa931:
       name: gps500
       rate: -2423.0
       win: 475.931766690695
       loss: 1720.65416034238
       rating_group: 0
-      last_modified: 2008-05-08 23:40:19 +09:00
-    usa_test+0c6049789d5fa11db9785155258b93b5: 
+      last_modified: 2008-05-08 23:40:19.000000000 +09:00
+    usa_test+0c6049789d5fa11db9785155258b93b5:
       name: usa_test
       rate: -2303.0
       win: 596.726845953427
       loss: 1486.33022716432
       rating_group: 0
-      last_modified: 2008-05-02 16:15:29 +09:00
-    tomi900+ff3ccfad330a8731a7a1100d2c081489: 
+      last_modified: 2008-05-02 16:15:29.000000000 +09:00
+    tomi900+ff3ccfad330a8731a7a1100d2c081489:
       name: tomi900
       rate: -2376.0
       win: 8.10630245430416
       loss: 13.8584073745703
       rating_group: 0
-      last_modified: 2008-02-14 23:24:09 +09:00
-    gps_kf+3301824de7e4a161724564abf32f0363: 
+      last_modified: 2008-02-14 23:24:09.000000000 +09:00
+    gps_kf+3301824de7e4a161724564abf32f0363:
       name: gps_kf
       rate: 2884.0
       win: 20.0
       loss: 19.9995076024558
       rating_group: 0
-      last_modified: 2008-05-03 01:24:13 +09:00
-    gps_qtseemc+1706abae91c059ba3ffed3dc9c9cfe1d: 
+      last_modified: 2008-05-03 01:24:13.000000000 +09:00
+    gps_qtseemc+1706abae91c059ba3ffed3dc9c9cfe1d:
       name: gps_qtseemc
       rate: 2763.0
       win: 8.07708612911955
       loss: 16.1424457840462
       rating_group: 0
-      last_modified: 2008-04-05 15:57:36 +09:00
-    usapyon-on-note+0c6049789d5fa11db9785155258b93b5: 
+      last_modified: 2008-04-05 15:57:36.000000000 +09:00
+    usapyon-on-note+0c6049789d5fa11db9785155258b93b5:
       name: usapyon-on-note
       rate: -2375.0
       win: 229.550829494412
       loss: 672.106457095826
       rating_group: 0
-      last_modified: 2008-04-23 20:45:22 +09:00
-    gps_cpu2+7641d40a2d4d4af7ddc9def42529ea9b: 
+      last_modified: 2008-04-23 20:45:22.000000000 +09:00
+    gps_cpu2+7641d40a2d4d4af7ddc9def42529ea9b:
       name: gps_cpu2
       rate: 3114.0
       win: 30.0789895320084
       loss: 23.2771098034858
       rating_group: 0
-      last_modified: 2008-04-02 16:29:35 +09:00
-    gps_lt3b+70dddf5a3ebd35efa71468c2e5e53691: 
+      last_modified: 2008-04-02 16:29:35.000000000 +09:00
+    gps_lt3b+70dddf5a3ebd35efa71468c2e5e53691:
       name: gps_lt3b
       rate: 2893.0
       win: 10.5484879004933
       loss: 10.0211511265367
       rating_group: 0
-      last_modified: 2008-03-08 03:11:48 +09:00
-    Nanoha2008+667f27d411182c654c12a55edc01460b: 
+      last_modified: 2008-03-08 03:11:48.000000000 +09:00
+    Nanoha2008+667f27d411182c654c12a55edc01460b:
       name: Nanoha2008
       last_game_win: false
       rate: -2786.0
       win: 3.0
       loss: 62.0
       rating_group: 0
-      last_modified: 2008-05-08 23:36:36 +09:00
-    tacos+282db3bc7edc88e4f182382c8b5cc147: 
+      last_modified: 2008-05-08 23:36:36.000000000 +09:00
+    tacos+282db3bc7edc88e4f182382c8b5cc147:
       name: tacos
       rate: -1818.0
       win: 657.754164439212
       loss: 355.565692600649
       rating_group: 0
-      last_modified: 2008-05-08 09:39:25 +09:00
-    ssp+21f52837bcc36952291e3ca14b75c1e8: 
+      last_modified: 2008-05-08 09:39:25.000000000 +09:00
+    ssp+21f52837bcc36952291e3ca14b75c1e8:
       name: ssp
       rate: -2535.0
       win: 50.2719100204888
       loss: 249.512660733661
       rating_group: 0
-      last_modified: 2008-04-30 20:48:33 +09:00
-    imai+81dc9bdb52d04dc20036dbd8313ed055: 
+      last_modified: 2008-04-30 20:48:33.000000000 +09:00
+    imai+81dc9bdb52d04dc20036dbd8313ed055:
       name: imai
       last_game_win: false
       rate: -2301.0
       win: 6.0
       loss: 20.0
       rating_group: 0
-      last_modified: 2008-05-08 22:36:40 +09:00
-    gps_tm+83f57ee9b210d4247a5ceb2e20bfbff8: 
+      last_modified: 2008-05-08 22:36:40.000000000 +09:00
+    gps_tm+83f57ee9b210d4247a5ceb2e20bfbff8:
       name: gps_tm
       rate: 2883.0
       win: 8.89521993921137
       loss: 8.90554984628389
       rating_group: 0
-      last_modified: 2008-02-26 23:49:17 +09:00
-    gps_cpu4rs+b0530c15c38c0d10e4d1e3ac00dba352: 
+      last_modified: 2008-02-26 23:49:17.000000000 +09:00
+    gps_cpu4rs+b0530c15c38c0d10e4d1e3ac00dba352:
       name: gps_cpu4rs
       rate: 3236.0
       win: 15.5527424717879
       loss: 14.7893992317924
       rating_group: 0
-      last_modified: 2008-04-10 15:49:03 +09:00
-    gps_newopening6_2dan+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-04-10 15:49:03.000000000 +09:00
+    gps_newopening6_2dan+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_newopening6_2dan
       rate: 2921.0
       win: 56.9834509073819
       loss: 45.987385502195
       rating_group: 0
-      last_modified: 2008-05-03 20:55:08 +09:00
-    coredump+8c0b2e8281d25adfb3a6bd4fdcae6e57: 
+      last_modified: 2008-05-03 20:55:08.000000000 +09:00
+    coredump+8c0b2e8281d25adfb3a6bd4fdcae6e57:
       name: coredump
       rate: -1984.0
       win: 459.776797445082
       loss: 337.429375313976
       rating_group: 0
-      last_modified: 2008-05-02 11:00:08 +09:00
-    Lesserkai+d800b2b8e356f4559ea3ba4519f11eff: 
+      last_modified: 2008-05-02 11:00:08.000000000 +09:00
+    Lesserkai+d800b2b8e356f4559ea3ba4519f11eff:
       name: Lesserkai
       rate: -3035.0
       win: 1.36585588490053
       loss: 93.0862283848441
       rating_group: 0
-      last_modified: 2008-04-12 18:08:04 +09:00
-    gps_kachi3+d4a19b7839aea28259fbb1071b5b352c: 
+      last_modified: 2008-04-12 18:08:04.000000000 +09:00
+    gps_kachi3+d4a19b7839aea28259fbb1071b5b352c:
       name: gps_kachi3
       rate: 2910.0
       win: 20.3186016436094
       loss: 17.4368835954953
       rating_group: 0
-      last_modified: 2008-04-29 20:47:48 +09:00
-    gps_mc+226caf236915aa9ae9a98b16514f9871: 
+      last_modified: 2008-04-29 20:47:48.000000000 +09:00
+    gps_mc+226caf236915aa9ae9a98b16514f9871:
       name: gps_mc
       rate: 2939.0
       win: 15.7890995446369
       loss: 11.4835823075585
       rating_group: 0
-      last_modified: 2008-04-03 19:11:21 +09:00
-    gps+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-04-03 19:11:21.000000000 +09:00
+    gps+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps
       rate: 2884.0
       win: 1175.66739199111
       loss: 1203.22715879058
       rating_group: 0
-      last_modified: 2008-05-08 23:31:31 +09:00
-    gps_pr8+5592a0e99b70a051fedcdbf5810334ef: 
+      last_modified: 2008-05-08 23:31:31.000000000 +09:00
+    gps_pr8+5592a0e99b70a051fedcdbf5810334ef:
       name: gps_pr8
       rate: 2950.0
       win: 13.9539803665413
       loss: 9.51999326841611
       rating_group: 0
-      last_modified: 2008-03-24 02:45:16 +09:00
-    gps_effect5x3const16+1268f1e5638290288bce86eabe09826c: 
+      last_modified: 2008-03-24 02:45:16.000000000 +09:00
+    gps_effect5x3const16+1268f1e5638290288bce86eabe09826c:
       name: gps_effect5x3const16
       rate: 2904.0
       win: 14.0017416718463
       loss: 12.4685158739091
       rating_group: 0
-      last_modified: 2008-04-10 18:44:22 +09:00
-    garyu+2e31d52fa05194cf8f2ad023ac572f09: 
+      last_modified: 2008-04-10 18:44:22.000000000 +09:00
+    garyu+2e31d52fa05194cf8f2ad023ac572f09:
       name: garyu
       rate: -2592.0
       win: 97.261418788048
       loss: 706.624377702383
       rating_group: 0
-      last_modified: 2008-05-03 01:49:54 +09:00
-    YSS+707d4f98d9d2620cdaab58f19d02a2e4: 
+      last_modified: 2008-05-03 01:49:54.000000000 +09:00
+    YSS+707d4f98d9d2620cdaab58f19d02a2e4:
       name: YSS
       rate: -1529.0
       win: 1012.14413170938
       loss: 121.533527986877
       rating_group: 0
-      last_modified: 2008-04-07 08:51:42 +09:00
-    KShogi900+d0426ce2e69157611ba5e225f4a92d11: 
+      last_modified: 2008-04-07 08:51:42.000000000 +09:00
+    KShogi900+d0426ce2e69157611ba5e225f4a92d11:
       name: KShogi900
       rate: -1768.0
       win: 387.398787408915
       loss: 145.420571829785
       rating_group: 0
-      last_modified: 2008-04-27 09:49:56 +09:00
-    gps_small_step_1+3eacd3587c056e61f7a34ac81b25f3a1: 
+      last_modified: 2008-04-27 09:49:56.000000000 +09:00
+    gps_small_step_1+3eacd3587c056e61f7a34ac81b25f3a1:
       name: gps_small_step_1
       rate: 2873.0
       win: 15.352514288629
       loss: 16.3427595653383
       rating_group: 0
-      last_modified: 2008-04-28 23:22:30 +09:00
-    gps_kh2+73cb40740074cde329b31fb6f7b0a2d1: 
+      last_modified: 2008-04-28 23:22:30.000000000 +09:00
+    gps_kh2+73cb40740074cde329b31fb6f7b0a2d1:
       name: gps_kh2
       rate: 2839.0
       win: 17.0
       loss: 22.0
       rating_group: 0
-      last_modified: 2008-05-04 00:33:13 +09:00
-    aleag1tst+3123059c1c816471780539f6b6b738dc: 
+      last_modified: 2008-05-04 00:33:13.000000000 +09:00
+    aleag1tst+3123059c1c816471780539f6b6b738dc:
       name: aleag1tst
       rate: -2463.0
       win: 9.48524456819644
       loss: 29.9907372901062
       rating_group: 0
-      last_modified: 2008-05-01 20:10:26 +09:00
-    gps_kh+f034f70ba869796cd6f953d84e85b9b8: 
+      last_modified: 2008-05-01 20:10:26.000000000 +09:00
+    gps_kh+f034f70ba869796cd6f953d84e85b9b8:
       name: gps_kh
       rate: 2872.0
       win: 13.9825518506586
       loss: 14.9874986816353
       rating_group: 0
-      last_modified: 2008-05-02 10:22:31 +09:00
-    gps_newopening4+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-05-02 10:22:31.000000000 +09:00
+    gps_newopening4+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_newopening4
       rate: 2810.0
       win: 57.3861518936011
       loss: 87.4893233925526
       rating_group: 0
-      last_modified: 2008-04-30 12:38:10 +09:00
-    gps_qtsee2+076ea545a9d74230e053400d043993d9: 
+      last_modified: 2008-04-30 12:38:10.000000000 +09:00
+    gps_qtsee2+076ea545a9d74230e053400d043993d9:
       name: gps_qtsee2
       rate: 2973.0
       win: 18.4240146179166
       loss: 11.0372650659614
       rating_group: 0
-      last_modified: 2008-04-06 01:02:34 +09:00
-    gps_lt3+a62314b60359500f4974c756b04d98e8: 
+      last_modified: 2008-04-06 01:02:34.000000000 +09:00
+    gps_lt3+a62314b60359500f4974c756b04d98e8:
       name: gps_lt3
       rate: 2876.0
       win: 10.9114049440672
       loss: 11.4125817038391
       rating_group: 0
-      last_modified: 2008-03-06 20:40:07 +09:00
-    gps_ce2l+970196b4e4c872321da146e7afe8f298: 
+      last_modified: 2008-03-06 20:40:07.000000000 +09:00
+    gps_ce2l+970196b4e4c872321da146e7afe8f298:
       name: gps_ce2l
       rate: 2833.0
       win: 8.12683984375216
       loss: 10.8520014353578
       rating_group: 0
-      last_modified: 2008-03-29 16:53:13 +09:00
-    gps_exp3o4+3066c53d1daa02af64e5590a2b0fc0d2: 
+      last_modified: 2008-03-29 16:53:13.000000000 +09:00
+    gps_exp3o4+3066c53d1daa02af64e5590a2b0fc0d2:
       name: gps_exp3o4
       rate: 2873.0
       win: 14.8469848849175
       loss: 15.8286221375783
       rating_group: 0
-      last_modified: 2008-05-01 11:45:01 +09:00
-    misaki-on-note+d9ffaac630ab2ae0e93674c1b505f1aa: 
+      last_modified: 2008-05-01 11:45:01.000000000 +09:00
+    misaki-on-note+d9ffaac630ab2ae0e93674c1b505f1aa:
       name: misaki-on-note
       rate: -2409.0
       win: 7.6867985801868
       loss: 13.6426899212265
       rating_group: 0
-      last_modified: 2008-02-18 13:45:41 +09:00
-    gps_open25+4d56adee9881b46fb4afbbd012927f77: 
+      last_modified: 2008-02-18 13:45:41.000000000 +09:00
+    gps_open25+4d56adee9881b46fb4afbbd012927f77:
       name: gps_open25
       rate: 2919.0
       win: 14.200925757193
       loss: 11.615577284037
       rating_group: 0
-      last_modified: 2008-03-25 14:06:12 +09:00
-    Kakinoki-Test+89704a19dfaea78d699800e63bef0dea: 
+      last_modified: 2008-03-25 14:06:12.000000000 +09:00
+    Kakinoki-Test+89704a19dfaea78d699800e63bef0dea:
       name: Kakinoki-Test
       last_game_win: false
       rate: -1781.0
       win: 1502.51399278973
       loss: 570.847036100743
       rating_group: 0
-      last_modified: 2008-05-08 23:16:21 +09:00
-    gps1000+e293220e3f8a3e59f79f6b0efffaa931: 
+      last_modified: 2008-05-08 23:16:21.000000000 +09:00
+    gps1000+e293220e3f8a3e59f79f6b0efffaa931:
       name: gps1000
       rate: -1837.0
       win: 33.513467493493
       loss: 12.472413919018
       rating_group: 0
-      last_modified: 2008-02-11 02:11:19 +09:00
-    gps_exp5o8+ee125a193a2ba9c1bf4f662a87494c2e: 
+      last_modified: 2008-02-11 02:11:19.000000000 +09:00
+    gps_exp5o8+ee125a193a2ba9c1bf4f662a87494c2e:
       name: gps_exp5o8
       rate: 2873.0
       win: 15.8338481766278
       loss: 16.814632622013
       rating_group: 0
-      last_modified: 2008-05-01 11:54:17 +09:00
-    yowai_gps+95908f6c18338f5340371f71523fc5e3: 
+      last_modified: 2008-05-01 11:54:17.000000000 +09:00
+    yowai_gps+95908f6c18338f5340371f71523fc5e3:
       name: yowai_gps
       rate: -2507.0
       win: 225.669212529662
       loss: 290.616556759499
       rating_group: 0
-      last_modified: 2008-05-08 02:10:38 +09:00
-    gps_qtseeapp+ca8836c54b39c7fef557966e19a45c4b: 
+      last_modified: 2008-05-08 02:10:38.000000000 +09:00
+    gps_qtseeapp+ca8836c54b39c7fef557966e19a45c4b:
       name: gps_qtseeapp
       rate: 2901.0
       win: 16.1716844095597
       loss: 14.6247159019338
       rating_group: 0
-      last_modified: 2008-04-09 21:08:37 +09:00
-    gps_kh3+d2663672168f8bb0598d79995b007685: 
+      last_modified: 2008-04-09 21:08:37.000000000 +09:00
+    gps_kh3+d2663672168f8bb0598d79995b007685:
       name: gps_kh3
       rate: 2884.0
       win: 20.0
       loss: 20.0
       rating_group: 0
-      last_modified: 2008-05-04 05:08:19 +09:00
-    gps_newopening+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-05-04 05:08:19.000000000 +09:00
+    gps_newopening+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_newopening
       rate: 2885.0
       win: 286.317698576181
       loss: 283.546448297247
       rating_group: 0
-      last_modified: 2008-03-24 12:46:27 +09:00
-    YSS-1s+707d4f98d9d2620cdaab58f19d02a2e4: 
+      last_modified: 2008-03-24 12:46:27.000000000 +09:00
+    YSS-1s+707d4f98d9d2620cdaab58f19d02a2e4:
       name: YSS-1s
       rate: -1794.0
       win: 65.3391219828853
       loss: 10.0415273195652
       rating_group: 0
-      last_modified: 2008-02-25 12:10:26 +09:00
-    gps800+e293220e3f8a3e59f79f6b0efffaa931: 
+      last_modified: 2008-02-25 12:10:26.000000000 +09:00
+    gps800+e293220e3f8a3e59f79f6b0efffaa931:
       name: gps800
       rate: -2037.0
       win: 154.968017134351
       loss: 112.015983590553
       rating_group: 0
-      last_modified: 2008-02-20 11:45:21 +09:00
-    gps_pr8nrc+9c818a715439bb58038ea13860fa67a4: 
+      last_modified: 2008-02-20 11:45:21.000000000 +09:00
+    gps_pr8nrc+9c818a715439bb58038ea13860fa67a4:
       name: gps_pr8nrc
       rate: 2983.0
       win: 15.2870195536467
       loss: 8.6458627298524
       rating_group: 0
-      last_modified: 2008-03-28 03:28:28 +09:00
-    gps_s3+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-03-28 03:28:28.000000000 +09:00
+    gps_s3+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_s3
       rate: 2910.0
       win: 63.0
       loss: 54.0
       rating_group: 0
-      last_modified: 2008-05-06 21:30:22 +09:00
-    gps_q5p30_2+b46f4b3b73dd9fe02be65a13fea11267: 
+      last_modified: 2008-05-06 21:30:22.000000000 +09:00
+    gps_q5p30_2+b46f4b3b73dd9fe02be65a13fea11267:
       name: gps_q5p30_2
       rate: 2923.0
       win: 9.91954762752418
       loss: 7.93089563712773
       rating_group: 0
-      last_modified: 2008-05-01 13:31:31 +09:00
-    gps_kachi2+aab2d27a867ba2a63a1f92ce999845f3: 
+      last_modified: 2008-05-01 13:31:31.000000000 +09:00
+    gps_kachi2+aab2d27a867ba2a63a1f92ce999845f3:
       name: gps_kachi2
       rate: 2918.0
       win: 20.8983310934689
       loss: 17.1026689105532
       rating_group: 0
-      last_modified: 2008-04-28 02:24:26 +09:00
-    misaki900+d9ffaac630ab2ae0e93674c1b505f1aa: 
+      last_modified: 2008-04-28 02:24:26.000000000 +09:00
+    misaki900+d9ffaac630ab2ae0e93674c1b505f1aa:
       name: misaki900
       rate: -2293.0
       win: 915.676971193636
       loss: 1742.47270086152
       rating_group: 0
-      last_modified: 2008-05-08 20:20:50 +09:00
-    gps_newopening5_2dan+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-05-08 20:20:50.000000000 +09:00
+    gps_newopening5_2dan+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_newopening5_2dan
       rate: 2978.0
       win: 30.7005284346696
       loss: 17.8061733102248
       rating_group: 0
-      last_modified: 2008-05-01 15:33:32 +09:00
-    tomi900+fc9505d3dd1ebdd726ad7d2d1fc17c42: 
+      last_modified: 2008-05-01 15:33:32.000000000 +09:00
+    tomi900+fc9505d3dd1ebdd726ad7d2d1fc17c42:
       name: tomi900
       rate: -2394.0
       win: 16.6734844869228
       loss: 41.0136210133544
       rating_group: 0
-      last_modified: 2008-02-17 18:24:33 +09:00
-    gps_qtsee2mc3+d891620d5f4f4e770f726dbbe471d04c: 
+      last_modified: 2008-02-17 18:24:33.000000000 +09:00
+    gps_qtsee2mc3+d891620d5f4f4e770f726dbbe471d04c:
       name: gps_qtsee2mc3
       rate: 2919.0
       win: 16.4187162582884
       loss: 13.4225518156186
       rating_group: 0
-      last_modified: 2008-04-07 03:52:09 +09:00
-    gps_see+243d91f6c72383cf5892a6f8fbb434c1: 
+      last_modified: 2008-04-07 03:52:09.000000000 +09:00
+    gps_see+243d91f6c72383cf5892a6f8fbb434c1:
       name: gps_see
       rate: 2902.0
       win: 11.410682224614
       loss: 10.2861901919957
       rating_group: 0
-      last_modified: 2008-03-14 23:33:43 +09:00
-    gps_qtseeareaplus+5b9d8f9e83727e96205e14dadd591991: 
+      last_modified: 2008-03-14 23:33:43.000000000 +09:00
+    gps_qtseeareaplus+5b9d8f9e83727e96205e14dadd591991:
       name: gps_qtseeareaplus
       rate: 2954.0
       win: 18.1971584089735
       loss: 12.1262337391889
       rating_group: 0
-      last_modified: 2008-04-08 13:24:48 +09:00
-    kiri-test+f6e396dc8eb6a1123ed65d7ddcc78243: 
+      last_modified: 2008-04-08 13:24:48.000000000 +09:00
+    kiri-test+f6e396dc8eb6a1123ed65d7ddcc78243:
       name: kiri-test
       rate: -2092.0
       win: 40.5473992591258
       loss: 37.9301462747398
       rating_group: 0
-      last_modified: 2008-04-27 13:50:45 +09:00
-    yowa_usa+0c6049789d5fa11db9785155258b93b5: 
+      last_modified: 2008-04-27 13:50:45.000000000 +09:00
+    yowa_usa+0c6049789d5fa11db9785155258b93b5:
       name: yowa_usa
       last_game_win: true
       rate: -2724.0
       win: 10.8629800426498
       loss: 161.737929496205
       rating_group: 0
-      last_modified: 2008-05-08 23:36:36 +09:00
-    gps_mc3+5cef59cf3430503dacd5d71122802791: 
+      last_modified: 2008-05-08 23:36:36.000000000 +09:00
+    gps_mc3+5cef59cf3430503dacd5d71122802791:
       name: gps_mc3
       rate: 2907.0
       win: 29.0023324106828
       loss: 25.2929762134241
       rating_group: 0
-      last_modified: 2008-04-06 23:50:56 +09:00
-    gps_ka8+13f69316942a7bb10b33769f4f6513c9: 
+      last_modified: 2008-04-06 23:50:56.000000000 +09:00
+    gps_ka8+13f69316942a7bb10b33769f4f6513c9:
       name: gps_ka8
       rate: 2780.0
       win: 10.9888205042163
       loss: 19.9828527944161
       rating_group: 0
-      last_modified: 2008-05-02 10:16:23 +09:00
-    gps_so+a143c0e9135d136d05f8f6c63953a3a3: 
+      last_modified: 2008-05-02 10:16:23.000000000 +09:00
+    gps_so+a143c0e9135d136d05f8f6c63953a3a3:
       name: gps_so
       rate: 2784.0
       win: 7.09254352512512
       loss: 12.6087468546625
       rating_group: 0
-      last_modified: 2008-04-11 16:53:45 +09:00
-    gps_np+3c3ed5c337e39d047bc524e8d8eb0c6b: 
+      last_modified: 2008-04-11 16:53:45.000000000 +09:00
+    gps_np+3c3ed5c337e39d047bc524e8d8eb0c6b:
       name: gps_np
       rate: 2864.0
       win: 14.3060572181627
       loss: 15.9983548226445
       rating_group: 0
-      last_modified: 2008-04-17 13:34:11 +09:00
-    gps_pp2+1028f7b380e75bd54a5adb6de266e90d: 
+      last_modified: 2008-04-17 13:34:11.000000000 +09:00
+    gps_pp2+1028f7b380e75bd54a5adb6de266e90d:
       name: gps_pp2
       rate: 2825.0
       win: 10.0
       loss: 14.0
       rating_group: 0
-      last_modified: 2008-05-08 16:07:05 +09:00
-    cat18_on_note+1a3871214cdb95f2f7f9e2910c4cf3bb: 
+      last_modified: 2008-05-08 16:07:05.000000000 +09:00
+    cat18_on_note+1a3871214cdb95f2f7f9e2910c4cf3bb:
       name: cat18_on_note
       rate: -2385.0
       win: 158.469804422715
       loss: 474.828163150174
       rating_group: 0
-      last_modified: 2008-04-20 14:23:15 +09:00
-    MyMove900+94a2fb7f864ae656bdf9ed1d1dae3a3c: 
+      last_modified: 2008-04-20 14:23:15.000000000 +09:00
+    MyMove900+94a2fb7f864ae656bdf9ed1d1dae3a3c:
       name: MyMove900
       last_game_win: true
       rate: -2253.0
       win: 1360.66968921526
       loss: 2363.83249839534
       rating_group: 0
-      last_modified: 2008-05-08 23:53:26 +09:00
-    gps_mc00+67fe440a10c121de46c4276fc6332b7a: 
+      last_modified: 2008-05-08 23:53:26.000000000 +09:00
+    gps_mc00+67fe440a10c121de46c4276fc6332b7a:
       name: gps_mc00
       rate: 2884.0
       win: 11.7897169909261
       loss: 11.7839083830482
       rating_group: 0
-      last_modified: 2008-04-11 12:15:31 +09:00
-    gps_pfo+eafbd3c8c3c02fbc307b9ee9be81dd3d: 
+      last_modified: 2008-04-11 12:15:31.000000000 +09:00
+    gps_pfo+eafbd3c8c3c02fbc307b9ee9be81dd3d:
       name: gps_pfo
       rate: -2473.0
       win: 269.0
       loss: 221.0
       rating_group: 0
-      last_modified: 2008-05-05 19:14:12 +09:00
-    cat10+4bf1d145889d0e2410b76cefb149a404: 
+      last_modified: 2008-05-05 19:14:12.000000000 +09:00
+    cat10+4bf1d145889d0e2410b76cefb149a404:
       name: cat10
       rate: -2387.0
       win: 149.082727062101
       loss: 315.274052558195
       rating_group: 0
-      last_modified: 2008-04-05 18:46:36 +09:00
-    spear900_note+0de01547572775761f6eb2b9ec59dbae: 
+      last_modified: 2008-04-05 18:46:36.000000000 +09:00
+    spear900_note+0de01547572775761f6eb2b9ec59dbae:
       name: spear900_note
       rate: -2103.0
       win: 247.103632012203
       loss: 251.852475537186
       rating_group: 0
-      last_modified: 2008-05-02 07:07:38 +09:00
-    bingo+7859e4cc481f9487f5d45e6ade7a2518: 
+      last_modified: 2008-05-02 07:07:38.000000000 +09:00
+    bingo+7859e4cc481f9487f5d45e6ade7a2518:
       name: bingo
       last_game_win: false
       rate: -1623.0
       win: 1208.89734617365
       loss: 237.437390949787
       rating_group: 0
-      last_modified: 2008-05-01 03:38:47 +09:00
-    gps_mc2+ef32e1eeadb591be032ffd87fa8f3aab: 
+      last_modified: 2008-05-01 03:38:47.000000000 +09:00
+    gps_mc2+ef32e1eeadb591be032ffd87fa8f3aab:
       name: gps_mc2
       rate: 2804.0
       win: 8.7152292056957
       loss: 13.7960054306812
       rating_group: 0
-      last_modified: 2008-04-04 17:11:44 +09:00
-    gps_open25_20+d70e3f7b088ccfd310962bb37fc975ac: 
+      last_modified: 2008-04-04 17:11:44.000000000 +09:00
+    gps_open25_20+d70e3f7b088ccfd310962bb37fc975ac:
       name: gps_open25_20
       rate: 2931.0
       win: 13.7364342241624
       loss: 10.4680907249845
       rating_group: 0
-      last_modified: 2008-03-26 16:27:46 +09:00
-    gps_cpu4+1990ca8a73acba0401f325228d8c4f96: 
+      last_modified: 2008-03-26 16:27:46.000000000 +09:00
+    gps_cpu4+1990ca8a73acba0401f325228d8c4f96:
       name: gps_cpu4
       rate: 3227.0
       win: 47.9581993943147
       loss: 33.4593638353841
       rating_group: 0
-      last_modified: 2008-04-29 06:53:19 +09:00
-    gps_cpu4tbb+d631d551c7b87d36905f46167caa41c5: 
+      last_modified: 2008-04-29 06:53:19.000000000 +09:00
+    gps_cpu4tbb+d631d551c7b87d36905f46167caa41c5:
       name: gps_cpu4tbb
       rate: 3127.0
       win: 8.68479132982944
       loss: 15.4436996507596
       rating_group: 0
-      last_modified: 2008-04-29 06:53:19 +09:00
-    gps_cc2+e178cc4ceb7f69ca039aa46c746f18bf: 
+      last_modified: 2008-04-29 06:53:19.000000000 +09:00
+    gps_cc2+e178cc4ceb7f69ca039aa46c746f18bf:
       name: gps_cc2
       rate: 2866.0
       win: 17.7971465882009
       loss: 19.6880419042549
       rating_group: 0
-      last_modified: 2008-04-26 21:59:53 +09:00
-    gps_effect5x3func7+57ddcc5f075d66a422fc7037f92e91a1: 
+      last_modified: 2008-04-26 21:59:53.000000000 +09:00
+    gps_effect5x3func7+57ddcc5f075d66a422fc7037f92e91a1:
       name: gps_effect5x3func7
       rate: 2894.0
       win: 14.1843881597541
       loss: 13.386632664677
       rating_group: 0
-      last_modified: 2008-04-11 23:58:09 +09:00
-    gps_seenr+734797905c1a9e6d1ad64f19c31a1e1d: 
+      last_modified: 2008-04-11 23:58:09.000000000 +09:00
+    gps_seenr+734797905c1a9e6d1ad64f19c31a1e1d:
       name: gps_seenr
       rate: 2921.0
       win: 11.7279128495228
       loss: 9.48396449634873
       rating_group: 0
-      last_modified: 2008-03-13 01:51:12 +09:00
-    gps_step_100+69a935e4287879be46f83b2817b46f85: 
+      last_modified: 2008-03-13 01:51:12.000000000 +09:00
+    gps_step_100+69a935e4287879be46f83b2817b46f85:
       name: gps_step_100
       rate: 2884.0
       win: 16.9991860852941
       loss: 16.9976980786016
       rating_group: 0
-      last_modified: 2008-05-02 22:06:19 +09:00
-    spearCSA2008+417e7849a8ac94c94202e7d821db9b7e: 
+      last_modified: 2008-05-02 22:06:19.000000000 +09:00
+    spearCSA2008+417e7849a8ac94c94202e7d821db9b7e:
       name: spearCSA2008
       last_game_win: true
       rate: -2019.0
       win: 27.0
       loss: 12.0
       rating_group: 0
-      last_modified: 2008-05-08 23:50:54 +09:00
-    gps_qtseeplus+223748d30f3f8b7efa3423de12a6bd96: 
+      last_modified: 2008-05-08 23:50:54.000000000 +09:00
+    gps_qtseeplus+223748d30f3f8b7efa3423de12a6bd96:
       name: gps_qtseeplus
       rate: 2918.0
       win: 16.7028105818679
       loss: 13.6749889028838
       rating_group: 0
-      last_modified: 2008-04-08 16:51:59 +09:00
-  11: 
-    gps3_p+dea40e920b32ad920881f840ca1fecf0: 
+      last_modified: 2008-04-08 16:51:59.000000000 +09:00
+  11:
+    gps3_p+dea40e920b32ad920881f840ca1fecf0:
       name: gps3_p
       rate: 926.0
       win: 6.0
       loss: 14.0
       rating_group: 11
-      last_modified: 2008-05-04 23:45:59 +09:00
-    gps3_pke7+a8472716b65c248d7283308f8b085acc: 
+      last_modified: 2008-05-04 23:45:59.000000000 +09:00
+    gps3_pke7+a8472716b65c248d7283308f8b085acc:
       name: gps3_pke7
       rate: 1073.0
       win: 14.0
       loss: 6.0
       rating_group: 11
-      last_modified: 2008-05-04 23:45:59 +09:00
-  6: 
-    gps0_mpke+bb9f7923189236268b0bfee73e995729: 
+      last_modified: 2008-05-04 23:45:59.000000000 +09:00
+  6:
+    gps0_mpke+bb9f7923189236268b0bfee73e995729:
       name: gps0_mpke
       rate: 971.0
       win: 8.77311662103004
       loss: 10.726403086889
       rating_group: 6
-      last_modified: 2008-04-30 01:57:00 +09:00
-    gps0+3db9f442857731ed6f858ac991bc90d5: 
+      last_modified: 2008-04-30 01:57:00.000000000 +09:00
+    gps0+3db9f442857731ed6f858ac991bc90d5:
       name: gps0
       last_game_win: true
       rate: 1006.0
       win: 40.6362611991685
       loss: 38.7001461662861
       rating_group: 6
-      last_modified: 2008-05-04 16:34:03 +09:00
-    gps0_epi+3d727b4e40d6345563da37a3f33c0c83: 
+      last_modified: 2008-05-04 16:34:03.000000000 +09:00
+    gps0_epi+3d727b4e40d6345563da37a3f33c0c83:
       name: gps0_epi
       rate: 936.0
       win: 8.0
       loss: 12.0
       rating_group: 6
-      last_modified: 2008-05-04 00:26:05 +09:00
-    gps0_kab6+67a1c27d42175909f3dfb4be9b34468d: 
+      last_modified: 2008-05-04 00:26:05.000000000 +09:00
+    gps0_kab6+67a1c27d42175909f3dfb4be9b34468d:
       name: gps0_kab6
       rate: 1114.0
       win: 13.0
       loss: 7.0
       rating_group: 6
-      last_modified: 2008-05-04 16:34:03 +09:00
-    gps0_epkm+5f692dd43863431e607e059122178b21: 
+      last_modified: 2008-05-04 16:34:03.000000000 +09:00
+    gps0_epkm+5f692dd43863431e607e059122178b21:
       name: gps0_epkm
       rate: 971.0
       win: 8.92702954525609
       loss: 10.9098581122795
       rating_group: 6
-      last_modified: 2008-05-01 13:46:06 +09:00
-  1: 
-    gps1_pmp6+7e4a98f5d21d0bfbdbf06c905a5ec76f: 
+      last_modified: 2008-05-01 13:46:06.000000000 +09:00
+  1:
+    gps1_pmp6+7e4a98f5d21d0bfbdbf06c905a5ec76f:
       name: gps1_pmp6
       rate: 980.0
       win: 8.73319292008062
       loss: 10.6748914106424
       rating_group: 1
-      last_modified: 2008-04-29 17:18:37 +09:00
-    gps0_epi2+585ee99a46f1453587ed4dbce7bf1712: 
+      last_modified: 2008-04-29 17:18:37.000000000 +09:00
+    gps0_epi2+585ee99a46f1453587ed4dbce7bf1712:
       name: gps0_epi2
       rate: 1015.0
       win: 11.0
       loss: 9.0
       rating_group: 1
-      last_modified: 2008-05-04 13:24:15 +09:00
-    gps1_pmpc10+886242d533721d4f6deb70ab99c65b8a: 
+      last_modified: 2008-05-04 13:24:15.000000000 +09:00
+    gps1_pmpc10+886242d533721d4f6deb70ab99c65b8a:
       name: gps1_pmpc10
       rate: 1027.0
       win: 11.2028891182806
       loss: 8.53709973211393
       rating_group: 1
-      last_modified: 2008-03-09 03:47:04 +09:00
-    gps0_ppbw+20c38aac12d0a0cdcd1a0a5a8aa4d6fa: 
+      last_modified: 2008-03-09 03:47:04.000000000 +09:00
+    gps0_ppbw+20c38aac12d0a0cdcd1a0a5a8aa4d6fa:
       name: gps0_ppbw
       rate: 980.0
       win: 9.80169607999749
       loss: 9.80612633695485
       rating_group: 1
-      last_modified: 2008-04-30 14:46:16 +09:00
-    gps0_pkte+da595ccd83a463811f6b606c066810d0: 
+      last_modified: 2008-04-30 14:46:16.000000000 +09:00
+    gps0_pkte+da595ccd83a463811f6b606c066810d0:
       name: gps0_pkte
       rate: 1087.0
       win: 11.4662095419876
       loss: 6.17743471733985
       rating_group: 1
-      last_modified: 2008-04-21 11:52:25 +09:00
-    gps1_pmp+16b30034aa230cb0390fbb4b9afb29d1: 
+      last_modified: 2008-04-21 11:52:25.000000000 +09:00
+    gps1_pmp+16b30034aa230cb0390fbb4b9afb29d1:
       name: gps1_pmp
       rate: 1108.0
       win: 11.0418289499423
       loss: 6.44561033853136
       rating_group: 1
-      last_modified: 2008-04-25 03:13:30 +09:00
-    gps1_pmp5+2dc0d15860881dad0c2048ba6046b3b3: 
+      last_modified: 2008-04-25 03:13:30.000000000 +09:00
+    gps1_pmp5+2dc0d15860881dad0c2048ba6046b3b3:
       name: gps1_pmp5
       rate: 1015.0
       win: 9.57992527409892
       loss: 9.57928748387886
       rating_group: 1
-      last_modified: 2008-04-28 14:55:23 +09:00
-    gps1_p+e2a4088894d38f53c579be64644aa0ce: 
+      last_modified: 2008-04-28 14:55:23.000000000 +09:00
+    gps1_p+e2a4088894d38f53c579be64644aa0ce:
       name: gps1_p
       rate: 1015.0
       win: 122.337709090737
       loss: 122.158686634462
       rating_group: 1
-      last_modified: 2008-05-04 09:18:24 +09:00
-    gps1_ppb+0ac9978c2bd7b19ab10a7aa1e2284cd5: 
+      last_modified: 2008-05-04 09:18:24.000000000 +09:00
+    gps1_ppb+0ac9978c2bd7b19ab10a7aa1e2284cd5:
       name: gps1_ppb
       rate: 1122.0
       win: 13.0
       loss: 7.0
       rating_group: 1
-      last_modified: 2008-05-02 19:40:39 +09:00
-    gps0_pmke+4e3c1830c160c63cd4450b84eb0b2f54: 
+      last_modified: 2008-05-02 19:40:39.000000000 +09:00
+    gps0_pmke+4e3c1830c160c63cd4450b84eb0b2f54:
       name: gps0_pmke
       rate: 1088.0
       win: 12.323826352781
       loss: 6.62244088559627
       rating_group: 1
-      last_modified: 2008-04-27 15:41:40 +09:00
-    gps1_pmp4+c08b10fe0f713d9dd64c7b46abe8ec37: 
+      last_modified: 2008-04-27 15:41:40.000000000 +09:00
+    gps1_pmp4+c08b10fe0f713d9dd64c7b46abe8ec37:
       name: gps1_pmp4
       rate: 774.0
       win: 3.77791937551651
       loss: 15.1395135795855
       rating_group: 1
-      last_modified: 2008-04-27 12:10:25 +09:00
-    gps0_pnpee2+93f19f509fe12c6f49d3a1e6a0b2e725: 
+      last_modified: 2008-04-27 12:10:25.000000000 +09:00
+    gps0_pnpee2+93f19f509fe12c6f49d3a1e6a0b2e725:
       name: gps0_pnpee2
       rate: 909.0
       win: 7.4117785398901
       loss: 11.1196619009622
       rating_group: 1
-      last_modified: 2008-04-25 17:35:14 +09:00
-    gps1_ppabb3+e6df1c5175209f2ddbc537401eae0052: 
+      last_modified: 2008-04-25 17:35:14.000000000 +09:00
+    gps1_ppabb3+e6df1c5175209f2ddbc537401eae0052:
       name: gps1_ppabb3
       rate: 909.0
       win: 12.0874241992837
       loss: 18.14354756741
       rating_group: 1
-      last_modified: 2008-04-08 10:50:53 +09:00
-    gps1_pmp3+9b3a277d62350375b0d1b5a3e8b501e0: 
+      last_modified: 2008-04-08 10:50:53.000000000 +09:00
+    gps1_pmp3+9b3a277d62350375b0d1b5a3e8b501e0:
       name: gps1_pmp3
       rate: 1050.0
       win: 10.281108847505
       loss: 8.42133796130253
       rating_group: 1
-      last_modified: 2008-04-26 11:45:15 +09:00
-    gps1_pkj+bf60767768e6a99e06734e7365c2f1ee: 
+      last_modified: 2008-04-26 11:45:15.000000000 +09:00
+    gps1_pkj+bf60767768e6a99e06734e7365c2f1ee:
       name: gps1_pkj
       rate: 980.0
       win: 9.0
       loss: 11.0
       rating_group: 1
-      last_modified: 2008-05-03 12:18:29 +09:00
-    gps1_pe2+2f8973d8d3e301ca5819a8c6cf650e1a: 
+      last_modified: 2008-05-03 12:18:29.000000000 +09:00
+    gps1_pe2+2f8973d8d3e301ca5819a8c6cf650e1a:
       name: gps1_pe2
       rate: 1015.0
       win: 15.2959586162338
       loss: 14.2828692000647
       rating_group: 1
-      last_modified: 2008-04-30 14:12:40 +09:00
-    gps0_pbsm+7fd35123ccaa14f67462976d22fb2810: 
+      last_modified: 2008-04-30 14:12:40.000000000 +09:00
+    gps0_pbsm+7fd35123ccaa14f67462976d22fb2810:
       name: gps0_pbsm
       rate: 909.0
       win: 7.7450965938711
       loss: 11.6441019024452
       rating_group: 1
-      last_modified: 2008-04-29 15:33:50 +09:00
-    gps0_pkte2+996384f8b2baf98042196c0990aff956: 
+      last_modified: 2008-04-29 15:33:50.000000000 +09:00
+    gps0_pkte2+996384f8b2baf98042196c0990aff956:
       name: gps0_pkte2
       rate: 1015.0
       win: 9.84562219563632
       loss: 8.06071389199098
       rating_group: 1
-      last_modified: 2008-04-22 18:45:12 +09:00
-    gps0_pnpee+9d1358e53dcab6368c74a6c556e2ae09: 
+      last_modified: 2008-04-22 18:45:12.000000000 +09:00
+    gps0_pnpee+9d1358e53dcab6368c74a6c556e2ae09:
       name: gps0_pnpee
       rate: 945.0
       win: 8.25074808692898
       loss: 10.0901391336692
       rating_group: 1
-      last_modified: 2008-04-24 22:42:36 +09:00
-    gps0_pnpef+6a7f1956f921cc8ab4b2d123f14f6ac4: 
+      last_modified: 2008-04-24 22:42:36.000000000 +09:00
+    gps0_pnpef+6a7f1956f921cc8ab4b2d123f14f6ac4:
       name: gps0_pnpef
       rate: 980.0
       win: 9.06187135480589
       loss: 9.06017127503476
       rating_group: 1
-      last_modified: 2008-04-23 19:43:55 +09:00
-    gps1_pcx+5b2e1a61c9dc9a869ab14d5a8d98e74d: 
+      last_modified: 2008-04-23 19:43:55.000000000 +09:00
+    gps1_pcx+5b2e1a61c9dc9a869ab14d5a8d98e74d:
       name: gps1_pcx
       rate: 980.0
       win: 7.95923156541008
       loss: 9.72718755194501
       rating_group: 1
-      last_modified: 2008-04-21 16:46:36 +09:00
-    gps1_ppabb2+d07da6400758989888fff3fcbb4a938c: 
+      last_modified: 2008-04-21 16:46:36.000000000 +09:00
+    gps1_ppabb2+d07da6400758989888fff3fcbb4a938c:
       name: gps1_ppabb2
       rate: 1030.0
       win: 14.8422787892135
       loss: 11.1303228560631
       rating_group: 1
-      last_modified: 2008-04-06 18:52:41 +09:00
-    gps0_pmkb+815a8899b63276bec38b8c54886fe355: 
+      last_modified: 2008-04-06 18:52:41.000000000 +09:00
+    gps0_pmkb+815a8899b63276bec38b8c54886fe355:
       name: gps0_pmkb
       rate: 1127.0
       win: 13.1421706174191
       loss: 5.63133448814683
       rating_group: 1
-      last_modified: 2008-04-26 20:02:50 +09:00
-    gps0_pke5+facace91f58b19e1bd54f788d5601f47: 
+      last_modified: 2008-04-26 20:02:50.000000000 +09:00
+    gps0_pke5+facace91f58b19e1bd54f788d5601f47:
       name: gps0_pke5
       rate: 980.0
       win: 9.92368849637954
       loss: 9.91752462603345
       rating_group: 1
-      last_modified: 2008-05-01 15:52:53 +09:00
-    gps0_p15rp2+e64ad2ae7fd1217425c8489d1e190668: 
+      last_modified: 2008-05-01 15:52:53.000000000 +09:00
+    gps0_p15rp2+e64ad2ae7fd1217425c8489d1e190668:
       name: gps0_p15rp2
       rate: 872.0
       win: 5.4791200834662
       loss: 10.1748393347354
       rating_group: 1
-      last_modified: 2008-04-11 03:35:30 +09:00
-    gps1_pepf+4aad5d94ef116c66f9d85dea66a5d5c9: 
+      last_modified: 2008-04-11 03:35:30.000000000 +09:00
+    gps1_pepf+4aad5d94ef116c66f9d85dea66a5d5c9:
       name: gps1_pepf
       rate: 1050.0
       win: 10.9287270917035
       loss: 8.93239341491624
       rating_group: 1
-      last_modified: 2008-05-01 17:02:54 +09:00
-    gps1_pmp2+eaf775d96a8a33ca7d935c65e4bf6792: 
+      last_modified: 2008-05-01 17:02:54.000000000 +09:00
+    gps1_pmp2+eaf775d96a8a33ca7d935c65e4bf6792:
       name: gps1_pmp2
       rate: 994.0
       win: 7.41429387801882
       loss: 8.34541679222178
       rating_group: 1
-      last_modified: 2008-04-25 18:55:17 +09:00
-    gps1_pnpe+0ab166cc8ae68837ce39031ed949df91: 
+      last_modified: 2008-04-25 18:55:17.000000000 +09:00
+    gps1_pnpe+0ab166cc8ae68837ce39031ed949df91:
       name: gps1_pnpe
       rate: 1122.0
       win: 11.6353971180556
       loss: 6.27379905956942
       rating_group: 1
-      last_modified: 2008-04-22 19:04:02 +09:00
-    gps0_ppkd2+bf6912b6dbd47900a79d5c1fb792dd52: 
+      last_modified: 2008-04-22 19:04:02.000000000 +09:00
+    gps0_ppkd2+bf6912b6dbd47900a79d5c1fb792dd52:
       name: gps0_ppkd2
       rate: 945.0
       win: 9.0
       loss: 11.0
       rating_group: 1
-      last_modified: 2008-05-06 00:26:20 +09:00
-    gps1_pkd+92b2e371254e093ee41288d99d68ee29: 
+      last_modified: 2008-05-06 00:26:20.000000000 +09:00
+    gps1_pkd+92b2e371254e093ee41288d99d68ee29:
       name: gps1_pkd
       rate: 980.0
       win: 9.0
       loss: 11.0
       rating_group: 1
-      last_modified: 2008-05-04 09:18:24 +09:00
-    gps0_p+d5b7ec89ea83deaece5f6e0a5fcdfad7: 
+      last_modified: 2008-05-04 09:18:24.000000000 +09:00
+    gps0_p+d5b7ec89ea83deaece5f6e0a5fcdfad7:
       name: gps0_p
       rate: 980.0
       win: 160.600056350417
       loss: 168.073317052044
       rating_group: 1
-      last_modified: 2008-05-06 00:26:20 +09:00
-  7: 
-    gps1_epf2+3d5b65bb7f12ad93dacf6c6a590a4dfb: 
+      last_modified: 2008-05-06 00:26:20.000000000 +09:00
+  7:
+    gps1_epf2+3d5b65bb7f12ad93dacf6c6a590a4dfb:
       name: gps1_epf2
       rate: 1063.0
       win: 11.9546345439284
       loss: 7.96566841464449
       rating_group: 7
-      last_modified: 2008-05-01 23:18:14 +09:00
-    gps1_epf3+259d1309f956da0c489fa1e2b927cd9c: 
+      last_modified: 2008-05-01 23:18:14.000000000 +09:00
+    gps1_epf3+259d1309f956da0c489fa1e2b927cd9c:
       name: gps1_epf3
       rate: 1027.0
       win: 11.0
       loss: 9.0
       rating_group: 7
-      last_modified: 2008-05-03 09:16:56 +09:00
-    gps1_kd2+856d95db222350404da567880e3a3485: 
+      last_modified: 2008-05-03 09:16:56.000000000 +09:00
+    gps1_kd2+856d95db222350404da567880e3a3485:
       name: gps1_kd2
       rate: 958.0
       win: 9.0
       loss: 11.0
       rating_group: 7
-      last_modified: 2008-05-04 08:44:44 +09:00
-    gps1_e4+b2edfcc33e14f5a5041b9ba1bcc08c3c: 
+      last_modified: 2008-05-04 08:44:44.000000000 +09:00
+    gps1_e4+b2edfcc33e14f5a5041b9ba1bcc08c3c:
       name: gps1_e4
       rate: 957.0
       win: 8.82659124938429
       loss: 10.7904097029538
       rating_group: 7
-      last_modified: 2008-04-30 15:15:39 +09:00
-    gps1+5df059ccf2eda413600fc00081cc3d54: 
+      last_modified: 2008-04-30 15:15:39.000000000 +09:00
+    gps1+5df059ccf2eda413600fc00081cc3d54:
       name: gps1
       rate: 992.0
       win: 38.7560781175983
       loss: 40.7812257933127
       rating_group: 7
-      last_modified: 2008-05-04 08:44:44 +09:00
-  2: 
-    gps6_pebv+527147c9835290f6c5ddc5b9ddb35666: 
+      last_modified: 2008-05-04 08:44:44.000000000 +09:00
+  2:
+    gps6_pebv+527147c9835290f6c5ddc5b9ddb35666:
       name: gps6_pebv
       rate: 982.0
       win: 8.83377589213516
       loss: 10.800285846288
       rating_group: 2
-      last_modified: 2008-04-30 17:48:51 +09:00
-    gps6_pw4+02ee4810f85e8a88b088f4561be4cb83: 
+      last_modified: 2008-04-30 17:48:51.000000000 +09:00
+    gps6_pw4+02ee4810f85e8a88b088f4561be4cb83:
       name: gps6_pw4
       rate: 909.0
       win: 7.0
       loss: 13.0
       rating_group: 2
-      last_modified: 2008-05-08 03:54:12 +09:00
-    gps7_pkeu2+06cf8d45cd8db00554aa81d08bbbed21: 
+      last_modified: 2008-05-08 03:54:12.000000000 +09:00
+    gps7_pkeu2+06cf8d45cd8db00554aa81d08bbbed21:
       name: gps7_pkeu2
       rate: 979.0
       win: 9.95615463613726
       loss: 9.9613054078766
       rating_group: 2
-      last_modified: 2008-05-01 22:18:55 +09:00
-    gps7_p+edcd30db6362262ddb5c42327c96bcdc: 
+      last_modified: 2008-05-01 22:18:55.000000000 +09:00
+    gps7_p+edcd30db6362262ddb5c42327c96bcdc:
       name: gps7_p
       rate: 979.0
       win: 54.77840245852
       loss: 57.306261169016
       rating_group: 2
-      last_modified: 2008-05-04 09:45:39 +09:00
-    gps6_rp3+9ac0b1cb4eb5b51c1062bd97d0a47ef4: 
+      last_modified: 2008-05-04 09:45:39.000000000 +09:00
+    gps6_rp3+9ac0b1cb4eb5b51c1062bd97d0a47ef4:
       name: gps6_rp3
       rate: 1017.0
       win: 10.0
       loss: 10.0
       rating_group: 2
-      last_modified: 2008-05-04 16:51:42 +09:00
-    gps6_pw3+a53d6169ee0c70812da62c5251ddb25d: 
+      last_modified: 2008-05-04 16:51:42.000000000 +09:00
+    gps6_pw3+a53d6169ee0c70812da62c5251ddb25d:
       name: gps6_pw3
       rate: 1017.0
       win: 10.0
       loss: 10.0
       rating_group: 2
-      last_modified: 2008-05-07 10:26:36 +09:00
-    gps7_pz2+705c4dbca749eb9d17ca07a73e2e04cb: 
+      last_modified: 2008-05-07 10:26:36.000000000 +09:00
+    gps7_pz2+705c4dbca749eb9d17ca07a73e2e04cb:
       name: gps7_pz2
       rate: 982.0
       win: 6.78177767981663
       loss: 8.280716551552
       rating_group: 2
-      last_modified: 2008-04-07 17:28:42 +09:00
-    gps6_ppb2+fa14f013a1cb083ad0da5dd3ed61cab6: 
+      last_modified: 2008-04-07 17:28:42.000000000 +09:00
+    gps6_ppb2+fa14f013a1cb083ad0da5dd3ed61cab6:
       name: gps6_ppb2
       rate: 1017.0
       win: 10.0
       loss: 10.0
       rating_group: 2
-      last_modified: 2008-05-03 11:58:11 +09:00
-    gps6_peb+42afc7b6b767396b1e83b355c0deea22: 
+      last_modified: 2008-05-03 11:58:11.000000000 +09:00
+    gps6_peb+42afc7b6b767396b1e83b355c0deea22:
       name: gps6_peb
       rate: 1125.0
       win: 12.6676118707801
       loss: 6.82195084311398
       rating_group: 2
-      last_modified: 2008-04-30 00:47:07 +09:00
-    gps7_pkab4+99f0133905fb05d3b6de0a469f382dd0: 
+      last_modified: 2008-04-30 00:47:07.000000000 +09:00
+    gps7_pkab4+99f0133905fb05d3b6de0a469f382dd0:
       name: gps7_pkab4
       rate: 909.0
       win: 8.0
       loss: 12.0
       rating_group: 2
-      last_modified: 2008-05-04 09:45:39 +09:00
-    gps6_peb3+2a699ef355a01127ed97fa7efca111f4: 
+      last_modified: 2008-05-04 09:45:39.000000000 +09:00
+    gps6_peb3+2a699ef355a01127ed97fa7efca111f4:
       name: gps6_peb3
       rate: 1088.0
       win: 11.9100572426239
       loss: 7.93522543019853
       rating_group: 2
-      last_modified: 2008-05-01 15:56:46 +09:00
-    gps6_psmf2+0d49e10c9175e6600d84cf8511a9e8d0: 
+      last_modified: 2008-05-01 15:56:46.000000000 +09:00
+    gps6_psmf2+0d49e10c9175e6600d84cf8511a9e8d0:
       name: gps6_psmf2
       rate: 1017.0
       win: 7.87765342522577
       loss: 7.88207025636964
       rating_group: 2
-      last_modified: 2008-04-11 15:56:58 +09:00
-    gps7_pep+121fdf8ca75a59cc152c19c67e2daed4: 
+      last_modified: 2008-04-11 15:56:58.000000000 +09:00
+    gps7_pep+121fdf8ca75a59cc152c19c67e2daed4:
       name: gps7_pep
       rate: 1086.0
       win: 12.7525997544867
       loss: 6.87280643894678
       rating_group: 2
-      last_modified: 2008-04-30 17:29:38 +09:00
-    gps6_p+94b2b9d94ed461ab4b4053a2d4c4a114: 
+      last_modified: 2008-04-30 17:29:38.000000000 +09:00
+    gps6_p+94b2b9d94ed461ab4b4053a2d4c4a114:
       name: gps6_p
       last_game_win: true
       rate: 1017.0
       win: 131.734394623725
       loss: 122.431671775223
       rating_group: 2
-      last_modified: 2008-05-08 23:51:37 +09:00
-    gps7_pkab+fd61ed1b7ae0cc7c862c6386cb8a3644: 
+      last_modified: 2008-05-08 23:51:37.000000000 +09:00
+    gps7_pkab+fd61ed1b7ae0cc7c862c6386cb8a3644:
       name: gps7_pkab
       rate: 924.0
       win: 8.0
       loss: 11.0
       rating_group: 2
-      last_modified: 2008-05-02 19:13:06 +09:00
-    gps7_pz3+b69d94a2f5764780061eb9dd7d8a79a6: 
+      last_modified: 2008-05-02 19:13:06.000000000 +09:00
+    gps7_pz3+b69d94a2f5764780061eb9dd7d8a79a6:
       name: gps7_pz3
       rate: 1017.0
       win: 7.61059534994535
       loss: 7.62017859056819
       rating_group: 2
-      last_modified: 2008-04-08 17:13:41 +09:00
-    gps6_pw2+92b472c3f617095009fed8960f5670a4: 
+      last_modified: 2008-04-08 17:13:41.000000000 +09:00
+    gps6_pw2+92b472c3f617095009fed8960f5670a4:
       name: gps6_pw2
       rate: 909.0
       win: 7.0
       loss: 13.0
       rating_group: 2
-      last_modified: 2008-05-06 15:16:35 +09:00
-    gps6_psmf+01b42ab957311139e07ede84f547355b: 
+      last_modified: 2008-05-06 15:16:35.000000000 +09:00
+    gps6_psmf+01b42ab957311139e07ede84f547355b:
       name: gps6_psmf
       rate: 1017.0
       win: 7.80590970299945
       loss: 7.79646032724219
       rating_group: 2
-      last_modified: 2008-04-10 20:27:18 +09:00
-  8: 
-    gps6_akt+c3100b3aa28d7219a8cf5c11e977526e: 
+      last_modified: 2008-04-10 20:27:18.000000000 +09:00
+  8:
+    gps6_akt+c3100b3aa28d7219a8cf5c11e977526e:
       name: gps6_akt
       rate: 1081.0
       win: 13.0
       loss: 6.0
       rating_group: 8
-      last_modified: 2008-05-03 08:37:56 +09:00
-    gps6_rp2+fc6cfcea7623c03a83b53089ba8c5ae8: 
+      last_modified: 2008-05-03 08:37:56.000000000 +09:00
+    gps6_rp2+fc6cfcea7623c03a83b53089ba8c5ae8:
       name: gps6_rp2
       rate: 982.0
       win: 11.0
       loss: 9.0
       rating_group: 8
-      last_modified: 2008-05-04 13:29:22 +09:00
-    gps6_pw6+712bd16b4a856f9d6a193c868621347d: 
+      last_modified: 2008-05-04 13:29:22.000000000 +09:00
+    gps6_pw6+712bd16b4a856f9d6a193c868621347d:
       name: gps6_pw6
       last_game_win: true
       rate: 989.0
       win: 14.0
       loss: 11.0
       rating_group: 8
-      last_modified: 2008-05-08 23:14:25 +09:00
-    gps6+d915e85b03226884d42e5602373dfd02: 
+      last_modified: 2008-05-08 23:14:25.000000000 +09:00
+    gps6+d915e85b03226884d42e5602373dfd02:
       name: gps6
       last_game_win: false
       rate: 947.0
       win: 26.0
       loss: 38.0
       rating_group: 8
-      last_modified: 2008-05-08 23:14:25 +09:00
-  3: 
-    gps4_pmkke2+da66a3260b9799655b3a797320752305: 
+      last_modified: 2008-05-08 23:14:25.000000000 +09:00
+  3:
+    gps4_pmkke2+da66a3260b9799655b3a797320752305:
       name: gps4_pmkke2
       rate: 1022.0
       win: 9.56652811778896
       loss: 9.57133999095356
       rating_group: 3
-      last_modified: 2008-04-28 11:36:01 +09:00
-    gps4_pkep+3e887935d6b823165b5ef06ffc31e7ee: 
+      last_modified: 2008-04-28 11:36:01.000000000 +09:00
+    gps4_pkep+3e887935d6b823165b5ef06ffc31e7ee:
       name: gps4_pkep
       rate: 951.0
       win: 7.35253627034135
       loss: 11.0644423115383
       rating_group: 3
-      last_modified: 2008-04-25 06:48:44 +09:00
-    gps4_p+53ee4319f15f9cae0b108de6befac23b: 
+      last_modified: 2008-04-25 06:48:44.000000000 +09:00
+    gps4_p+53ee4319f15f9cae0b108de6befac23b:
       name: gps4_p
       rate: 1022.0
       win: 64.9417662122736
       loss: 55.9935568106017
       rating_group: 3
-      last_modified: 2008-04-28 11:36:01 +09:00
-    gps4_paebf5+0bef04a983e064f6f81b74582576ea2b: 
+      last_modified: 2008-04-28 11:36:01.000000000 +09:00
+    gps4_paebf5+0bef04a983e064f6f81b74582576ea2b:
       name: gps4_paebf5
       rate: 1022.0
       win: 7.73684061157097
       loss: 7.73566466353795
       rating_group: 3
-      last_modified: 2008-04-10 02:20:50 +09:00
-    gps4_paebf4+b01dbad724eb48420ccdb2a7e4cb22ad: 
+      last_modified: 2008-04-10 02:20:50.000000000 +09:00
+    gps4_paebf4+b01dbad724eb48420ccdb2a7e4cb22ad:
       name: gps4_paebf4
       rate: 987.0
       win: 6.88429453628398
       loss: 8.41980869197081
       rating_group: 3
-      last_modified: 2008-04-09 03:03:04 +09:00
-    gps4_paebf2+5e73acb18c0edf18355c1b8bc5c6e22c: 
+      last_modified: 2008-04-09 03:03:04.000000000 +09:00
+    gps4_paebf2+5e73acb18c0edf18355c1b8bc5c6e22c:
       name: gps4_paebf2
       rate: 1022.0
       win: 7.51827645124211
       loss: 7.51802897203015
       rating_group: 3
-      last_modified: 2008-04-07 14:04:23 +09:00
-    gps4_pmkke+a479c9c94175d5b52bb10612e9f922b9: 
+      last_modified: 2008-04-07 14:04:23.000000000 +09:00
+    gps4_pmkke+a479c9c94175d5b52bb10612e9f922b9:
       name: gps4_pmkke
       rate: 1057.0
       win: 10.4245996233114
       loss: 8.52445975437956
       rating_group: 3
-      last_modified: 2008-04-27 15:54:25 +09:00
-    gps4_pkep2+caa2af4cf9c0d28c06c3d70fd1bc473d: 
+      last_modified: 2008-04-27 15:54:25.000000000 +09:00
+    gps4_pkep2+caa2af4cf9c0d28c06c3d70fd1bc473d:
       name: gps4_pkep2
       rate: 914.0
       win: 6.51048120006291
       loss: 12.1080218278633
       rating_group: 3
-      last_modified: 2008-04-26 03:17:00 +09:00
-  9: 
-    gps_cpu2p30_2+15defe6c4af0b3e5e174a310dd06ebf4: 
+      last_modified: 2008-04-26 03:17:00.000000000 +09:00
+  9:
+    gps_cpu2p30_2+15defe6c4af0b3e5e174a310dd06ebf4:
       name: gps_cpu2p30_2
       rate: 1034.0
       win: 14.495785804564
       loss: 13.0494578486005
       rating_group: 9
-      last_modified: 2008-04-04 12:49:22 +09:00
-    gps_cpu2p30+06dacba1b8567acc21c488080ea413c3: 
+      last_modified: 2008-04-04 12:49:22.000000000 +09:00
+    gps_cpu2p30+06dacba1b8567acc21c488080ea413c3:
       name: gps_cpu2p30
       rate: 981.0
       win: 13.0308146635658
       loss: 15.9408731430726
       rating_group: 9
-      last_modified: 2008-04-04 10:59:08 +09:00
-    gps_cpu2p+574e90d7b2abe343a75b8c1cfeed5ff3: 
+      last_modified: 2008-04-04 10:59:08.000000000 +09:00
+    gps_cpu2p+574e90d7b2abe343a75b8c1cfeed5ff3:
       name: gps_cpu2p
       rate: 966.0
       win: 6.46147592240348
       loss: 8.61783504348173
       rating_group: 9
-      last_modified: 2008-04-03 14:02:43 +09:00
-    gpsp+20d6b4b22597e621dc2f1fb39197d948: 
+      last_modified: 2008-04-03 14:02:43.000000000 +09:00
+    gpsp+20d6b4b22597e621dc2f1fb39197d948:
       name: gpsp
       rate: 1016.0
       win: 37.6081660351548
       loss: 33.9880763905332
       rating_group: 9
-      last_modified: 2008-04-06 12:20:43 +09:00
-  999: 
-    gps7_ppabI3+0272537aeed684c58bc1104033e34aa0: 
+      last_modified: 2008-04-06 12:20:43.000000000 +09:00
+  999:
+    gps7_ppabI3+0272537aeed684c58bc1104033e34aa0:
       name: gps7_ppabI3
       rate: 0
       win: 2.37413854405468
       loss: 4.75192340608516
       rating_group: 999
-      last_modified: 2008-02-12 00:49:37 +09:00
-    gps7_pmk2+9c1c35a453346f0b5b664949689c98b8: 
+      last_modified: 2008-02-12 00:49:37.000000000 +09:00
+    gps7_pmk2+9c1c35a453346f0b5b664949689c98b8:
       name: gps7_pmk2
       rate: 0
       win: 7.19734717659165
       loss: 3.08348905396196
       rating_group: 999
-      last_modified: 2008-03-05 11:04:57 +09:00
-    gps_do+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-03-05 11:04:57.000000000 +09:00
+    gps_do+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_do
       rate: 0
       win: 5.97558324489925
       loss: 0.994988766801764
       rating_group: 999
-      last_modified: 2008-05-01 16:55:51 +09:00
-    gps7_pmk3+a3f122a05091ce9f0939de99d96b114d: 
+      last_modified: 2008-05-01 16:55:51.000000000 +09:00
+    gps7_pmk3+a3f122a05091ce9f0939de99d96b114d:
       name: gps7_pmk3
       rate: 0
       win: 4.16049011364312
       loss: 6.23719503773664
       rating_group: 999
-      last_modified: 2008-03-06 15:16:05 +09:00
-    gps7_kab2+ad71e0fa23c82c9f87e6e6884a07b129: 
+      last_modified: 2008-03-06 15:16:05.000000000 +09:00
+    gps7_kab2+ad71e0fa23c82c9f87e6e6884a07b129:
       name: gps7_kab2
       rate: 0
       win: 0.0
       loss: 1.0
       rating_group: 999
-      last_modified: 2008-05-02 15:09:19 +09:00
-    gps4_paebf3+0126f06215f43b87402ccadd720169e4: 
+      last_modified: 2008-05-02 15:09:19.000000000 +09:00
+    gps4_paebf3+0126f06215f43b87402ccadd720169e4:
       name: gps4_paebf3
       rate: 0
       win: 2.27910114803295
       loss: 6.8444977266173
       rating_group: 999
-      last_modified: 2008-04-08 10:46:12 +09:00
-    gps6_pw7+80058cfe0f6cd26a4118ed60b9b67154: 
+      last_modified: 2008-04-08 10:46:12.000000000 +09:00
+    gps6_pw7+80058cfe0f6cd26a4118ed60b9b67154:
       name: gps6_pw7
       last_game_win: false
       rate: 0
       win: 4.0
       loss: 3.0
       rating_group: 999
-      last_modified: 2008-05-08 23:51:37 +09:00
-    gps_pr8s3+2a1dd56e1d9ed3a626c737bcdee3ca49: 
+      last_modified: 2008-05-08 23:51:37.000000000 +09:00
+    gps_pr8s3+2a1dd56e1d9ed3a626c737bcdee3ca49:
       name: gps_pr8s3
       rate: 0
       win: 1.95129196539734
       loss: 4.55762133499333
       rating_group: 999
-      last_modified: 2008-03-25 22:39:21 +09:00
-    matomoni+50a6348c667759604bc4ff9247c11473: 
+      last_modified: 2008-03-25 22:39:21.000000000 +09:00
+    matomoni+50a6348c667759604bc4ff9247c11473:
       name: matomoni
       rate: 0
       win: 0.0
       loss: 13.007470167874
       rating_group: 999
-      last_modified: 2008-05-05 22:07:24 +09:00
-    gps1_pmpc2+e142c4bbdf75e8ae0331dad77d0f98eb: 
+      last_modified: 2008-05-05 22:07:24.000000000 +09:00
+    gps1_pmpc2+e142c4bbdf75e8ae0331dad77d0f98eb:
       name: gps1_pmpc2
       rate: 0
       win: 5.63947581946014
       loss: 3.07398447031382
       rating_group: 999
-      last_modified: 2008-03-05 09:31:45 +09:00
-    test1+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-03-05 09:31:45.000000000 +09:00
+    test1+098f6bcd4621d373cade4e832627b4f6:
       name: test1
       rate: 0
       win: 0.0
       loss: 1.31785860451171
       rating_group: 999
-      last_modified: 2008-03-26 21:15:42 +09:00
-    test1+47bce5c74f589f4867dbd57e9ca9f808: 
+      last_modified: 2008-03-26 21:15:42.000000000 +09:00
+    test1+47bce5c74f589f4867dbd57e9ca9f808:
       name: test1
       rate: 0
       win: 2.39816368022251
       loss: 1.19658441710944
       rating_group: 999
-      last_modified: 2008-02-12 18:59:40 +09:00
-    gps1_pnp+2a8efcf93fe5946869e4f31fa3c36a7a: 
+      last_modified: 2008-02-12 18:59:40.000000000 +09:00
+    gps1_pnp+2a8efcf93fe5946869e4f31fa3c36a7a:
       name: gps1_pnp
       rate: 0
       win: 4.92911996634997
       loss: 3.57902285620133
       rating_group: 999
-      last_modified: 2008-02-22 17:24:41 +09:00
-    pc2+c4ca4238a0b923820dcc509a6f75849b: 
+      last_modified: 2008-02-22 17:24:41.000000000 +09:00
+    pc2+c4ca4238a0b923820dcc509a6f75849b:
       name: pc2
       rate: 0
       win: 4.18171068842216
       loss: 2.74689869667087
       rating_group: 999
-      last_modified: 2008-03-11 22:28:00 +09:00
-    misaki900+8fb8876e8bb2125c004ded950d8bbb67: 
+      last_modified: 2008-03-11 22:28:00.000000000 +09:00
+    misaki900+8fb8876e8bb2125c004ded950d8bbb67:
       name: misaki900
       rate: 0
       win: 3.0
       loss: 5.99867526631817
       rating_group: 999
-      last_modified: 2008-05-02 02:39:23 +09:00
-    gps1_pka3+e996af61ebb5e773bb5f6eaeedb6f399: 
+      last_modified: 2008-05-02 02:39:23.000000000 +09:00
+    gps1_pka3+e996af61ebb5e773bb5f6eaeedb6f399:
       name: gps1_pka3
       rate: 0
       win: 3.21009672369634
       loss: 4.01530826585413
       rating_group: 999
-      last_modified: 2008-02-13 04:44:24 +09:00
-    gps6_pw+1d7aebda92dce3ad0ce3fd218e8bfcff: 
+      last_modified: 2008-02-13 04:44:24.000000000 +09:00
+    gps6_pw+1d7aebda92dce3ad0ce3fd218e8bfcff:
       name: gps6_pw
       rate: 0
       win: 1.0
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-05-05 21:49:00 +09:00
-    pc2+92eb5ffee6ae2fec3ad71c777531578f: 
+      last_modified: 2008-05-05 21:49:00.000000000 +09:00
+    pc2+92eb5ffee6ae2fec3ad71c777531578f:
       name: pc2
       rate: 0
       win: 1.36018889195079
       loss: 0.387278490318016
       rating_group: 999
-      last_modified: 2008-03-30 11:08:12 +09:00
-    gps7_psee2+82121163db0812c49f26279d42febd4e: 
+      last_modified: 2008-03-30 11:08:12.000000000 +09:00
+    gps7_psee2+82121163db0812c49f26279d42febd4e:
       name: gps7_psee2
       rate: 0
       win: 4.05059795826744
       loss: 5.57366777190387
       rating_group: 999
-      last_modified: 2008-03-04 09:08:38 +09:00
-    gps7_pmpc+a8189b0f3742350ee20e2caba0808441: 
+      last_modified: 2008-03-04 09:08:38.000000000 +09:00
+    gps7_pmpc+a8189b0f3742350ee20e2caba0808441:
       name: gps7_pmpc
       rate: 0
       win: 3.46975464137791
       loss: 7.63073259993943
       rating_group: 999
-      last_modified: 2008-03-31 14:33:38 +09:00
-    gps4_pmpc+37ee2322482bbb586663be8e8cf47e6d: 
+      last_modified: 2008-03-31 14:33:38.000000000 +09:00
+    gps4_pmpc+37ee2322482bbb586663be8e8cf47e6d:
       name: gps4_pmpc
       rate: 0
       win: 5.08024006179467
       loss: 3.55085944910098
       rating_group: 999
-      last_modified: 2008-03-04 12:42:10 +09:00
-    pc2+a87ff679a2f3e71d9181a67b7542122c: 
+      last_modified: 2008-03-04 12:42:10.000000000 +09:00
+    pc2+a87ff679a2f3e71d9181a67b7542122c:
       name: pc2
       rate: 0
       win: 0.54172245849132
       loss: 3.26461164467359
       rating_group: 999
-      last_modified: 2008-03-11 22:52:07 +09:00
-    gps2_p+d8a9eeb8a2501b81581be0d57677c145: 
+      last_modified: 2008-03-11 22:52:07.000000000 +09:00
+    gps2_p+d8a9eeb8a2501b81581be0d57677c145:
       name: gps2_p
       rate: 0
       win: 12.5717996135362
       loss: 12.4612707575602
       rating_group: 999
-      last_modified: 2008-03-04 12:42:10 +09:00
-    pc1+e4da3b7fbbce2345d7772b0674a318d5: 
+      last_modified: 2008-03-04 12:42:10.000000000 +09:00
+    pc1+e4da3b7fbbce2345d7772b0674a318d5:
       name: pc1
       rate: 0
       win: 4.43605643445131
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-03-11 22:52:23 +09:00
-    ymshogi_test+61b2c94ea07eda40cfc396e9ae7286cf: 
+      last_modified: 2008-03-11 22:52:23.000000000 +09:00
+    ymshogi_test+61b2c94ea07eda40cfc396e9ae7286cf:
       name: ymshogi_test
       rate: 0
       win: 0.966399854105744
       loss: 53.9649846244257
       rating_group: 999
-      last_modified: 2008-05-03 05:07:58 +09:00
-    gps1_pmpc3+e39b448ccdd53108ed5367db5ee2776a: 
+      last_modified: 2008-05-03 05:07:58.000000000 +09:00
+    gps1_pmpc3+e39b448ccdd53108ed5367db5ee2776a:
       name: gps1_pmpc3
       rate: 0
       win: 5.16523260869099
       loss: 3.60899376668153
       rating_group: 999
-      last_modified: 2008-03-06 00:28:24 +09:00
-    misaki+d9ffaac630ab2ae0e93674c1b505f1aa: 
+      last_modified: 2008-03-06 00:28:24.000000000 +09:00
+    misaki+d9ffaac630ab2ae0e93674c1b505f1aa:
       name: misaki
       last_game_win: false
       rate: 0
       win: 4.85072439857614
       loss: 3.85093185852652
       rating_group: 999
-      last_modified: 2008-05-08 23:40:19 +09:00
-    gps1_pe+57225819b01bcd9494ba5c69f15552c3: 
+      last_modified: 2008-05-08 23:40:19.000000000 +09:00
+    gps1_pe+57225819b01bcd9494ba5c69f15552c3:
       name: gps1_pe
       rate: 0
       win: 4.93804003702345
       loss: 4.94716343109585
       rating_group: 999
-      last_modified: 2008-03-02 05:49:24 +09:00
-    yoshiki+5058f1af8388633f609cadb75a75dc9d: 
+      last_modified: 2008-03-02 05:49:24.000000000 +09:00
+    yoshiki+5058f1af8388633f609cadb75a75dc9d:
       name: yoshiki
       rate: 0
       win: 0.0
       loss: 1.86668664677574
       rating_group: 999
-      last_modified: 2008-03-21 22:20:11 +09:00
-    ovo2+25bbdcd06c32d477f7fa1c3e4a91b032: 
+      last_modified: 2008-03-21 22:20:11.000000000 +09:00
+    ovo2+25bbdcd06c32d477f7fa1c3e4a91b032:
       name: ovo2
       rate: 0
       win: 0.0
       loss: 48.237522040793
       rating_group: 999
-      last_modified: 2008-05-02 13:12:12 +09:00
-    gps1_pnpg+ea2a4e4f1c8469f37299aa535f397adb: 
+      last_modified: 2008-05-02 13:12:12.000000000 +09:00
+    gps1_pnpg+ea2a4e4f1c8469f37299aa535f397adb:
       name: gps1_pnpg
       rate: 0
       win: 3.25890841273782
       loss: 5.58228591589497
       rating_group: 999
-      last_modified: 2008-02-26 00:01:03 +09:00
-    kaneko-test2+c1d518f5c51f59cfcdfa6fd0d74011d1: 
+      last_modified: 2008-02-26 00:01:03.000000000 +09:00
+    kaneko-test2+c1d518f5c51f59cfcdfa6fd0d74011d1:
       name: kaneko-test2
       rate: 0
       win: 3.24425845783411
       loss: 0.540731006296224
       rating_group: 999
-      last_modified: 2008-03-09 18:25:44 +09:00
-    gps1_pr88+736974779028c8a9ae369c40b99f4bab: 
+      last_modified: 2008-03-09 18:25:44.000000000 +09:00
+    gps1_pr88+736974779028c8a9ae369c40b99f4bab:
       name: gps1_pr88
       rate: 0
       win: 3.92435650239876
       loss: 2.74763123663178
       rating_group: 999
-      last_modified: 2008-02-11 06:50:53 +09:00
-    gps0_p15rp+21e0d6345a0afd3f8a9464337fc70f81: 
+      last_modified: 2008-02-11 06:50:53.000000000 +09:00
+    gps0_p15rp+21e0d6345a0afd3f8a9464337fc70f81:
       name: gps0_p15rp
       rate: 0
       win: 1.55571521000306
       loss: 3.89169575116332
       rating_group: 999
-      last_modified: 2008-04-10 09:34:05 +09:00
-    Ayaka2007+7052b1f054caaaf7769f15fccfdc4798: 
+      last_modified: 2008-04-10 09:34:05.000000000 +09:00
+    Ayaka2007+7052b1f054caaaf7769f15fccfdc4798:
       name: Ayaka2007
       rate: 0
       win: 0.919586531359499
       loss: 16.5457426948978
       rating_group: 999
-      last_modified: 2008-02-25 03:44:04 +09:00
-    gps1_pnp3+be109baa51edd8d89c0de206a3895ae0: 
+      last_modified: 2008-02-25 03:44:04.000000000 +09:00
+    gps1_pnp3+be109baa51edd8d89c0de206a3895ae0:
       name: gps1_pnp3
       rate: 0
       win: 4.11184105119365
       loss: 4.11287148225036
       rating_group: 999
-      last_modified: 2008-02-24 10:07:30 +09:00
-    gps1_pmpc4+dc07789d1cf8f1dca6ab9a893c59bbb2: 
+      last_modified: 2008-02-24 10:07:30.000000000 +09:00
+    gps1_pmpc4+dc07789d1cf8f1dca6ab9a893c59bbb2:
       name: gps1_pmpc4
       rate: 0
       win: 5.20057471794151
       loss: 4.15923237999246
       rating_group: 999
-      last_modified: 2008-03-06 15:19:38 +09:00
-    GOD+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-03-06 15:19:38.000000000 +09:00
+    GOD+098f6bcd4621d373cade4e832627b4f6:
       name: GOD
       rate: 0
       win: 0.0
       loss: 1.43410183880869
       rating_group: 999
-      last_modified: 2008-03-14 22:48:17 +09:00
-    gps7_psa2+4089f050b68443af2a6f4986afc759f6: 
+      last_modified: 2008-03-14 22:48:17.000000000 +09:00
+    gps7_psa2+4089f050b68443af2a6f4986afc759f6:
       name: gps7_psa2
       rate: 0
       win: 4.41815546839211
       loss: 3.61211579954968
       rating_group: 999
-      last_modified: 2008-02-13 05:53:50 +09:00
-    gps0_ppkd+6321826bbd94fb62c7e4c99dc494db42: 
+      last_modified: 2008-02-13 05:53:50.000000000 +09:00
+    gps0_ppkd+6321826bbd94fb62c7e4c99dc494db42:
       name: gps0_ppkd
       rate: 0
       win: 3.0
       loss: 2.0
       rating_group: 999
-      last_modified: 2008-05-05 06:52:19 +09:00
-    gps1_ppabb+3d1e87fe095b83f982bfbddc5cec13e1: 
+      last_modified: 2008-05-05 06:52:19.000000000 +09:00
+    gps1_ppabb+3d1e87fe095b83f982bfbddc5cec13e1:
       name: gps1_ppabb
       rate: 0
       win: 6.24789639065473
       loss: 4.15965642161918
       rating_group: 999
-      last_modified: 2008-03-31 14:36:41 +09:00
-    tomcat+48bae5e28e7585ccdfad978d2ce056b2: 
+      last_modified: 2008-03-31 14:36:41.000000000 +09:00
+    tomcat+48bae5e28e7585ccdfad978d2ce056b2:
       name: tomcat
       rate: 0
       win: 1.46199582559984
       loss: 0.969582861500572
       rating_group: 999
-      last_modified: 2008-03-01 17:47:43 +09:00
-    your_program_name+1060b7b46a3bd36b3a0d66e0127d0517: 
+      last_modified: 2008-03-01 17:47:43.000000000 +09:00
+    your_program_name+1060b7b46a3bd36b3a0d66e0127d0517:
       name: your_program_name
       rate: 0
       win: 0.0
       loss: 1.8231757836041
       rating_group: 999
-      last_modified: 2008-04-23 23:47:35 +09:00
-    gps1_pe13+6cc12bf8490991d034d004731855b27f: 
+      last_modified: 2008-04-23 23:47:35.000000000 +09:00
+    gps1_pe13+6cc12bf8490991d034d004731855b27f:
       name: gps1_pe13
       rate: 0
       win: 0.504442859236656
       loss: 2.52431759752155
       rating_group: 999
-      last_modified: 2008-03-03 20:52:38 +09:00
-    gps7_pska+ed528aeabb3dccbdf53a5243888aadae: 
+      last_modified: 2008-03-03 20:52:38.000000000 +09:00
+    gps7_pska+ed528aeabb3dccbdf53a5243888aadae:
       name: gps7_pska
       rate: 0
       win: 3.67338779718212
       loss: 3.67339093111968
       rating_group: 999
-      last_modified: 2008-02-14 16:25:32 +09:00
-    gps7_psee3+c6cf70391c5f7877e82068c76ebf5b64: 
+      last_modified: 2008-02-14 16:25:32.000000000 +09:00
+    gps7_psee3+c6cf70391c5f7877e82068c76ebf5b64:
       name: gps7_psee3
       rate: 0
       win: 5.10990415683874
       loss: 5.100732957657
       rating_group: 999
-      last_modified: 2008-03-05 02:06:03 +09:00
-    TeamGPS+91d5d6d0427f78f20dbdc8e76007356d: 
+      last_modified: 2008-03-05 02:06:03.000000000 +09:00
+    TeamGPS+91d5d6d0427f78f20dbdc8e76007356d:
       name: TeamGPS
       rate: 0
       win: 1.0
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-05-04 02:26:43 +09:00
-    gps_qtseearea+73c32ddbeef3515fce4d71786c38ef71: 
+      last_modified: 2008-05-04 02:26:43.000000000 +09:00
+    gps_qtseearea+73c32ddbeef3515fce4d71786c38ef71:
       name: gps_qtseearea
       rate: 0
       win: 7.51134737969909
       loss: 5.25426201436594
       rating_group: 999
-      last_modified: 2008-04-07 10:15:59 +09:00
-    gps7_pmk+c118a5489ce33b97f4aeb0783b90a3a5: 
+      last_modified: 2008-04-07 10:15:59.000000000 +09:00
+    gps7_pmk+c118a5489ce33b97f4aeb0783b90a3a5:
       name: gps7_pmk
       rate: 0
       win: 5.13125988290303
       loss: 5.13019364054553
       rating_group: 999
-      last_modified: 2008-03-05 07:12:35 +09:00
-    gps7_pmpc2+6185c9d6c43dff3a2bef269b63a53eb7: 
+      last_modified: 2008-03-05 07:12:35.000000000 +09:00
+    gps7_pmpc2+6185c9d6c43dff3a2bef269b63a53eb7:
       name: gps7_pmpc2
       rate: 0
       win: 7.43363614746777
       loss: 7.44099697225586
       rating_group: 999
-      last_modified: 2008-04-06 16:23:30 +09:00
-    pc1+c4ca4238a0b923820dcc509a6f75849b: 
+      last_modified: 2008-04-06 16:23:30.000000000 +09:00
+    pc1+c4ca4238a0b923820dcc509a6f75849b:
       name: pc1
       rate: 0
       win: 4.80701091245275
       loss: 6.06830448939908
       rating_group: 999
-      last_modified: 2008-04-25 19:33:00 +09:00
-    test2+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-04-25 19:33:00.000000000 +09:00
+    test2+098f6bcd4621d373cade4e832627b4f6:
       name: test2
       rate: 0
       win: 1.31785860451171
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-03-26 21:15:42 +09:00
-    pc1+0cc175b9c0f1b6a831c399e269772661: 
+      last_modified: 2008-03-26 21:15:42.000000000 +09:00
+    pc1+0cc175b9c0f1b6a831c399e269772661:
       name: pc1
       rate: 0
       win: 0.387278490318016
       loss: 3.96740892622904
       rating_group: 999
-      last_modified: 2008-03-30 11:08:12 +09:00
-    gps7_psa+ca86319a6b0d196e3f387bf8f6242d63: 
+      last_modified: 2008-03-30 11:08:12.000000000 +09:00
+    gps7_psa+ca86319a6b0d196e3f387bf8f6242d63:
       name: gps7_psa
       rate: 0
       win: 4.38515241355686
       loss: 3.58513866015491
       rating_group: 999
-      last_modified: 2008-02-12 14:18:55 +09:00
-    kaneko-test+5058f1af8388633f609cadb75a75dc9d: 
+      last_modified: 2008-02-12 14:18:55.000000000 +09:00
+    kaneko-test+5058f1af8388633f609cadb75a75dc9d:
       name: kaneko-test
       rate: 0
       win: 0.0
       loss: 1.0
       rating_group: 999
-      last_modified: 2008-05-04 02:26:43 +09:00
-    GEPPER+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-05-04 02:26:43.000000000 +09:00
+    GEPPER+098f6bcd4621d373cade4e832627b4f6:
       name: GEPPER
       rate: 0
       win: 0.0
       loss: 21.7051709294456
       rating_group: 999
-      last_modified: 2008-05-06 23:42:28 +09:00
-    username1+5f4dcc3b5aa765d61d8327deb882cf99: 
+      last_modified: 2008-05-06 23:42:28.000000000 +09:00
+    username1+5f4dcc3b5aa765d61d8327deb882cf99:
       name: username1
       rate: 0
       win: 0.0
       loss: 21.7871556340513
       rating_group: 999
-      last_modified: 2008-03-04 02:04:18 +09:00
-    gps1_pkte+c8beae8bd7158b319a91b379c057b05f: 
+      last_modified: 2008-03-04 02:04:18.000000000 +09:00
+    gps1_pkte+c8beae8bd7158b319a91b379c057b05f:
       name: gps1_pkte
       rate: 0
       win: 5.02005760026863
       loss: 6.13723134166796
       rating_group: 999
-      last_modified: 2008-03-12 19:45:55 +09:00
-    pc2+03c7c0ace395d80182db07ae2c30f034: 
+      last_modified: 2008-03-12 19:45:55.000000000 +09:00
+    pc2+03c7c0ace395d80182db07ae2c30f034:
       name: pc2
       rate: 0
       win: 1.09512293936863
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-03-10 20:31:36 +09:00
-    ipa+43945d0d3e53ac07d91b0e0f59fd1e21: 
+      last_modified: 2008-03-10 20:31:36.000000000 +09:00
+    ipa+43945d0d3e53ac07d91b0e0f59fd1e21:
       name: ipa
       rate: 0
       win: 0.0
       loss: 1.37599301613844
       rating_group: 999
-      last_modified: 2008-03-30 14:57:21 +09:00
-    gps4_paebf+1fdaa09e7f9c16ed1091ee09428fc0ac: 
+      last_modified: 2008-03-30 14:57:21.000000000 +09:00
+    gps4_paebf+1fdaa09e7f9c16ed1091ee09428fc0ac:
       name: gps4_paebf
       rate: 0
       win: 6.69990403704951
       loss: 8.18551413932288
       rating_group: 999
-      last_modified: 2008-04-06 17:47:00 +09:00
-    gps1_pka+add01fb87e5a1293d005247c9387391c: 
+      last_modified: 2008-04-06 17:47:00.000000000 +09:00
+    gps1_pka+add01fb87e5a1293d005247c9387391c:
       name: gps1_pka
       rate: 0
       win: 3.95938224668317
       loss: 3.9603124754782
       rating_group: 999
-      last_modified: 2008-02-12 01:34:32 +09:00
-    R+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-02-12 01:34:32.000000000 +09:00
+    R+098f6bcd4621d373cade4e832627b4f6:
       name: R
       rate: 0
       win: 0.448143453067201
       loss: 2.24050154600835
       rating_group: 999
-      last_modified: 2008-02-22 12:20:16 +09:00
-    Ayaka2007+7dcac6e40988bcfa8407fc0744f6b64e: 
+      last_modified: 2008-02-22 12:20:16.000000000 +09:00
+    Ayaka2007+7dcac6e40988bcfa8407fc0744f6b64e:
       name: Ayaka2007
       rate: 0
       win: 0.0
       loss: 30.5649072804631
       rating_group: 999
-      last_modified: 2008-02-24 02:39:43 +09:00
-    gps4_pky+8a88b1752937def23cda64522ff3c077: 
+      last_modified: 2008-02-24 02:39:43.000000000 +09:00
+    gps4_pky+8a88b1752937def23cda64522ff3c077:
       name: gps4_pky
       rate: 0
       win: 3.64780525160742
       loss: 4.45632381394203
       rating_group: 999
-      last_modified: 2008-02-14 01:47:54 +09:00
-    kaneko+5058f1af8388633f609cadb75a75dc9d: 
+      last_modified: 2008-02-14 01:47:54.000000000 +09:00
+    kaneko+5058f1af8388633f609cadb75a75dc9d:
       name: kaneko
       rate: 0
       win: 0.0
       loss: 1.77449942396776
       rating_group: 999
-      last_modified: 2008-03-05 10:41:37 +09:00
-    gps_s2+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-03-05 10:41:37.000000000 +09:00
+    gps_s2+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps_s2
       rate: 0
       win: 2.0
       loss: 9.0
       rating_group: 999
-      last_modified: 2008-05-04 02:17:33 +09:00
-    gps8cpu+51ba10507fee37a907cda72bd63d72f0: 
+      last_modified: 2008-05-04 02:17:33.000000000 +09:00
+    gps8cpu+51ba10507fee37a907cda72bd63d72f0:
       name: gps8cpu
       rate: 0
       win: 4.97969982709647
       loss: 0.391750615406864
       rating_group: 999
-      last_modified: 2008-02-20 13:43:30 +09:00
-    pc1+a87ff679a2f3e71d9181a67b7542122c: 
+      last_modified: 2008-02-20 13:43:30.000000000 +09:00
+    pc1+a87ff679a2f3e71d9181a67b7542122c:
       name: pc1
       rate: 0
       win: 3.85595408171491
       loss: 3.13266127153545
       rating_group: 999
-      last_modified: 2008-03-11 22:50:59 +09:00
-    test2+47bce5c74f589f4867dbd57e9ca9f808: 
+      last_modified: 2008-03-11 22:50:59.000000000 +09:00
+    test2+47bce5c74f589f4867dbd57e9ca9f808:
       name: test2
       rate: 0
       win: 1.19658441710944
       loss: 2.39816368022251
       rating_group: 999
-      last_modified: 2008-02-12 18:59:40 +09:00
-    gps4_pkep3+de14ab38aba203fba5770eb28de528ea: 
+      last_modified: 2008-02-12 18:59:40.000000000 +09:00
+    gps4_pkep3+de14ab38aba203fba5770eb28de528ea:
       name: gps4_pkep3
       rate: 0
       win: 4.70323518646419
       loss: 8.46352764886076
       rating_group: 999
-      last_modified: 2008-04-26 22:15:24 +09:00
-    gps_kachi+3b91020198c46a8070fcbbe55c1f984b: 
+      last_modified: 2008-04-26 22:15:24.000000000 +09:00
+    gps_kachi+3b91020198c46a8070fcbbe55c1f984b:
       name: gps_kachi
       rate: 0
       win: 3.76781181342986
       loss: 6.59706844766145
       rating_group: 999
-      last_modified: 2008-04-26 23:52:45 +09:00
-    gps1_pmpc8+9678ca96f57cc5a75782a1145fc9987b: 
+      last_modified: 2008-04-26 23:52:45.000000000 +09:00
+    gps1_pmpc8+9678ca96f57cc5a75782a1145fc9987b:
       name: gps1_pmpc8
       rate: 0
       win: 4.71466137351621
       loss: 4.18614807675241
       rating_group: 999
-      last_modified: 2008-03-07 05:34:47 +09:00
-    gps_cpu4p16+561d1247b6b08664758faa68347cadaf: 
+      last_modified: 2008-03-07 05:34:47.000000000 +09:00
+    gps_cpu4p16+561d1247b6b08664758faa68347cadaf:
       name: gps_cpu4p16
       rate: 0
       win: 7.42949610697478
       loss: 5.94750065979917
       rating_group: 999
-      last_modified: 2008-04-06 12:20:43 +09:00
-    gps_8cpu+813015cab4287a23392e0082220c5805: 
+      last_modified: 2008-04-06 12:20:43.000000000 +09:00
+    gps_8cpu+813015cab4287a23392e0082220c5805:
       name: gps_8cpu
       rate: 0
       win: 5.0
       loss: 4.0
       rating_group: 999
-      last_modified: 2008-05-04 08:00:38 +09:00
-    gps30+813015cab4287a23392e0082220c5805: 
+      last_modified: 2008-05-04 08:00:38.000000000 +09:00
+    gps30+813015cab4287a23392e0082220c5805:
       name: gps30
       rate: 0
       win: 12.027391442297
       loss: 4.0
       rating_group: 999
-      last_modified: 2008-05-06 23:42:28 +09:00
-    gps_scr+58b813a0dc157dfdbeabd3afe7643726: 
+      last_modified: 2008-05-06 23:42:28.000000000 +09:00
+    gps_scr+58b813a0dc157dfdbeabd3afe7643726:
       name: gps_scr
       rate: 0
       win: 3.0
       loss: 6.0
       rating_group: 999
-      last_modified: 2008-05-08 23:18:02 +09:00
-    gps4_pbp+d81ba2e3205d35d0dd2d12be19bf9d67: 
+      last_modified: 2008-05-08 23:18:02.000000000 +09:00
+    gps4_pbp+d81ba2e3205d35d0dd2d12be19bf9d67:
       name: gps4_pbp
       rate: 0
       win: 3.73322544415813
       loss: 4.56461635049319
       rating_group: 999
-      last_modified: 2008-02-16 03:17:29 +09:00
-    gps1_pnp4+1d2710ee2228968ecffb0d7e7021c144: 
+      last_modified: 2008-02-16 03:17:29.000000000 +09:00
+    gps1_pnp4+1d2710ee2228968ecffb0d7e7021c144:
       name: gps1_pnp4
       rate: 0
       win: 3.22085262459041
       loss: 5.52555734219273
       rating_group: 999
-      last_modified: 2008-02-25 02:43:23 +09:00
-    usaoya+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-02-25 02:43:23.000000000 +09:00
+    usaoya+098f6bcd4621d373cade4e832627b4f6:
       name: usaoya
       rate: 0
       win: 0.574085339470999
       loss: 1.70599269116463
       rating_group: 999
-      last_modified: 2008-03-29 23:04:17 +09:00
-    gps1_pka4+94a4ef82f4f0dae7d12fcd9e9fa68dc7: 
+      last_modified: 2008-03-29 23:04:17.000000000 +09:00
+    gps1_pka4+94a4ef82f4f0dae7d12fcd9e9fa68dc7:
       name: gps1_pka4
       rate: 0
       win: 4.45559409749626
       loss: 3.6480188462149
       rating_group: 999
-      last_modified: 2008-02-14 01:36:38 +09:00
-    spear900+05b08566ff2ec028287189062e521d1d: 
+      last_modified: 2008-02-14 01:36:38.000000000 +09:00
+    spear900+05b08566ff2ec028287189062e521d1d:
       name: spear900
       rate: 0
       win: 9.05771994907118
       loss: 2.01414206050652
       rating_group: 999
-      last_modified: 2008-03-03 15:52:55 +09:00
-    mattari_yuchan_test+aac81b5c0cf7bf4b5842e3908a709502: 
+      last_modified: 2008-03-03 15:52:55.000000000 +09:00
+    mattari_yuchan_test+aac81b5c0cf7bf4b5842e3908a709502:
       name: mattari_yuchan_test
       last_game_win: false
       rate: 0
       win: 3.0
       loss: 10.0
       rating_group: 999
-      last_modified: 2008-05-08 23:53:26 +09:00
-    pc2+c81e728d9d4c2f636f067f89cc14862c: 
+      last_modified: 2008-05-08 23:53:26.000000000 +09:00
+    pc2+c81e728d9d4c2f636f067f89cc14862c:
       name: pc2
       rate: 0
       win: 3.28656026387904
       loss: 2.51707390348184
       rating_group: 999
-      last_modified: 2008-04-19 13:31:23 +09:00
-    yowai_gps_test+dcbd015b6d6271acedcd30b84453c353: 
+      last_modified: 2008-04-19 13:31:23.000000000 +09:00
+    yowai_gps_test+dcbd015b6d6271acedcd30b84453c353:
       name: yowai_gps_test
       rate: 0
       win: 0.0
       loss: 1.16300981411347
       rating_group: 999
-      last_modified: 2008-02-09 23:10:01 +09:00
-    gps1_pt+dbe4ea3ae48cb785bf92d670723c925a: 
+      last_modified: 2008-02-09 23:10:01.000000000 +09:00
+    gps1_pt+dbe4ea3ae48cb785bf92d670723c925a:
       name: gps1_pt
       rate: 0
       win: 2.49153833722485
       loss: 4.56017852061372
       rating_group: 999
-      last_modified: 2008-02-16 02:16:17 +09:00
-    gps1_pe3+6df8e3e8851329a1ca3ec14c33ba804b: 
+      last_modified: 2008-02-16 02:16:17.000000000 +09:00
+    gps1_pe3+6df8e3e8851329a1ca3ec14c33ba804b:
       name: gps1_pe3
       rate: 0
       win: 3.04228163567075
       loss: 7.10358487942135
       rating_group: 999
-      last_modified: 2008-03-04 13:54:33 +09:00
-    gps1_pg+0283617fd60191c1e333831b9c10defa: 
+      last_modified: 2008-03-04 13:54:33.000000000 +09:00
+    gps1_pg+0283617fd60191c1e333831b9c10defa:
       name: gps1_pg
       rate: 0
       win: 4.43060682067607
       loss: 3.54004292474244
       rating_group: 999
-      last_modified: 2008-02-21 18:13:59 +09:00
-    gps_exp16b+9f74478657f8a65175fc0f42489acc05: 
+      last_modified: 2008-02-21 18:13:59.000000000 +09:00
+    gps_exp16b+9f74478657f8a65175fc0f42489acc05:
       name: gps_exp16b
       rate: 0
       win: 0.0
       loss: 5.71503485564411
       rating_group: 999
-      last_modified: 2008-04-27 20:36:25 +09:00
-    gps8cpu+11648e4e66e7ed6a86cb7f1d0cf604fe: 
+      last_modified: 2008-04-27 20:36:25.000000000 +09:00
+    gps8cpu+11648e4e66e7ed6a86cb7f1d0cf604fe:
       name: gps8cpu
       rate: 0
       win: 9.76910925599213
       loss: 0.714102787732918
       rating_group: 999
-      last_modified: 2008-05-03 05:57:55 +09:00
-    gps7_ppabI2+024cc4c494638819aef73d6a71925d9c: 
+      last_modified: 2008-05-03 05:57:55.000000000 +09:00
+    gps7_ppabI2+024cc4c494638819aef73d6a71925d9c:
       name: gps7_ppabI2
       rate: 0
       win: 3.5323942549571
       loss: 3.52839482243325
       rating_group: 999
-      last_modified: 2008-02-11 04:41:19 +09:00
-    pc2+e4da3b7fbbce2345d7772b0674a318d5: 
+      last_modified: 2008-02-11 04:41:19.000000000 +09:00
+    pc2+e4da3b7fbbce2345d7772b0674a318d5:
       name: pc2
       rate: 0
       win: 0.96451771211084
       loss: 3.86918367231102
       rating_group: 999
-      last_modified: 2008-03-11 22:52:23 +09:00
-    misaki+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-03-11 22:52:23.000000000 +09:00
+    misaki+098f6bcd4621d373cade4e832627b4f6:
       name: misaki
       rate: 0
       win: 1.17483538100067
       loss: 3.13216359232655
       rating_group: 999
-      last_modified: 2008-02-10 20:09:45 +09:00
-    gps7_pz4+2820db5da30c537181cfacd23a04bec5: 
+      last_modified: 2008-02-10 20:09:45.000000000 +09:00
+    gps7_pz4+2820db5da30c537181cfacd23a04bec5:
       name: gps7_pz4
       rate: 0
       win: 6.13575163921137
       loss: 8.45396550690933
       rating_group: 999
-      last_modified: 2008-04-09 11:14:59 +09:00
-    ellecia2+3123059c1c816471780539f6b6b738dc: 
+      last_modified: 2008-04-09 11:14:59.000000000 +09:00
+    ellecia2+3123059c1c816471780539f6b6b738dc:
       name: ellecia2
       rate: 0
       win: 0.650607307852355
       loss: 1.22554823127326
       rating_group: 999
-      last_modified: 2008-03-25 18:48:46 +09:00
-    gps_pp10+cfa3292063eb247e51fd103e53999c85: 
+      last_modified: 2008-03-25 18:48:46.000000000 +09:00
+    gps_pp10+cfa3292063eb247e51fd103e53999c85:
       name: gps_pp10
       rate: 0
       win: 2.0
       loss: 3.0
       rating_group: 999
-      last_modified: 2008-05-08 23:24:58 +09:00
-    gps7_pmk4+4bf23894d31c124f683995d341faeb5b: 
+      last_modified: 2008-05-08 23:24:58.000000000 +09:00
+    gps7_pmk4+4bf23894d31c124f683995d341faeb5b:
       name: gps7_pmk4
       rate: 0
       win: 4.71389101336148
       loss: 5.76081264301408
       rating_group: 999
-      last_modified: 2008-03-07 07:02:21 +09:00
-    gps1_old+cbd6837c2403128221c7f65315a76928: 
+      last_modified: 2008-03-07 07:02:21.000000000 +09:00
+    gps1_old+cbd6837c2403128221c7f65315a76928:
       name: gps1_old
       rate: 0
       win: 4.07954455349915
       loss: 6.12004175552569
       rating_group: 999
-      last_modified: 2008-03-04 18:20:09 +09:00
-    gps7_pkeu+946dd752934d80e81a6c0588bb35ac6f: 
+      last_modified: 2008-03-04 18:20:09.000000000 +09:00
+    gps7_pkeu+946dd752934d80e81a6c0588bb35ac6f:
       name: gps7_pkeu
       rate: 0
       win: 0.99037817695798
       loss: 5.94458057622329
       rating_group: 999
-      last_modified: 2008-05-01 07:17:08 +09:00
-    kaneko-test1+c1d518f5c51f59cfcdfa6fd0d74011d1: 
+      last_modified: 2008-05-01 07:17:08.000000000 +09:00
+    kaneko-test1+c1d518f5c51f59cfcdfa6fd0d74011d1:
       name: kaneko-test1
       rate: 0
       win: 0.540731006296224
       loss: 3.24425845783411
       rating_group: 999
-      last_modified: 2008-03-09 18:25:44 +09:00
-    gps7_ppabI+58008bcbd80ec35321353dceaacd77ce: 
+      last_modified: 2008-03-09 18:25:44.000000000 +09:00
+    gps7_ppabI+58008bcbd80ec35321353dceaacd77ce:
       name: gps7_ppabI
       rate: 0
       win: 3.5034694912018
       loss: 3.50885823530829
       rating_group: 999
-      last_modified: 2008-02-10 16:27:57 +09:00
-    gps30_8cpu+813015cab4287a23392e0082220c5805: 
+      last_modified: 2008-02-10 16:27:57.000000000 +09:00
+    gps30_8cpu+813015cab4287a23392e0082220c5805:
       name: gps30_8cpu
       rate: 0
       win: 4.0
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-05-04 02:33:05 +09:00
-    gps_wcsc17+a213f8b2b86d4f1595c8c0de34e7f2e2: 
+      last_modified: 2008-05-04 02:33:05.000000000 +09:00
+    gps_wcsc17+a213f8b2b86d4f1595c8c0de34e7f2e2:
       name: gps_wcsc17
       rate: 0
       win: 0.0
       loss: 1.0
       rating_group: 999
-      last_modified: 2008-05-02 19:49:30 +09:00
-    misakitest+098f6bcd4621d373cade4e832627b4f6: 
+      last_modified: 2008-05-02 19:49:30.000000000 +09:00
+    misakitest+098f6bcd4621d373cade4e832627b4f6:
       name: misakitest
       rate: 0
       win: 3.13216359232655
       loss: 1.17483538100067
       rating_group: 999
-      last_modified: 2008-02-10 20:09:45 +09:00
-    gps7_pmk2-30+faf5199cadb7774bad74b17a5c6cc0a1: 
+      last_modified: 2008-02-10 20:09:45.000000000 +09:00
+    gps7_pmk2-30+faf5199cadb7774bad74b17a5c6cc0a1:
       name: gps7_pmk2-30
       rate: 0
       win: 4.64919706385219
       loss: 5.1591179437548
       rating_group: 999
-      last_modified: 2008-03-06 00:29:06 +09:00
-    gps1_pnp2+33bb7c6e4d09574114756ab1fff59f37: 
+      last_modified: 2008-03-06 00:29:06.000000000 +09:00
+    gps1_pnp2+33bb7c6e4d09574114756ab1fff59f37:
       name: gps1_pnp2
       rate: 0
       win: 4.07503051644584
       loss: 4.53050101342215
       rating_group: 999
-      last_modified: 2008-02-23 17:29:25 +09:00
-    gps7_psa3+a252b8b8cf94d378376c30efaa7e3c12: 
+      last_modified: 2008-02-23 17:29:25.000000000 +09:00
+    gps7_psa3+a252b8b8cf94d378376c30efaa7e3c12:
       name: gps7_psa3
       rate: 0
       win: 3.64638172435888
       loss: 3.64110823557492
       rating_group: 999
-      last_modified: 2008-02-13 23:04:38 +09:00
-    ssp+fe33467fa97283fd0c6e39106f020753: 
+      last_modified: 2008-02-13 23:04:38.000000000 +09:00
+    ssp+fe33467fa97283fd0c6e39106f020753:
       name: ssp
       rate: 0
       win: 0.0
       loss: 1.18879968181155
       rating_group: 999
-      last_modified: 2008-03-17 23:03:43 +09:00
-    gps_lg2+3460302ed6cc24fb91dcadab211b18b1: 
+      last_modified: 2008-03-17 23:03:43.000000000 +09:00
+    gps_lg2+3460302ed6cc24fb91dcadab211b18b1:
       name: gps_lg2
       rate: 0
       win: 6.16876149215196
       loss: 8.22146578496015
       rating_group: 999
-      last_modified: 2008-03-30 13:16:17 +09:00
-    gps1_pr68+ab84ca8c4c34df394ef67ddb8a55c575: 
+      last_modified: 2008-03-30 13:16:17.000000000 +09:00
+    gps1_pr68+ab84ca8c4c34df394ef67ddb8a55c575:
       name: gps1_pr68
       rate: 0
       win: 1.94971780216178
       loss: 5.06277266660577
       rating_group: 999
-      last_modified: 2008-02-10 15:52:23 +09:00
-    gps1_pka2+7033c93adba70e063c3b744929e6f7c8: 
+      last_modified: 2008-02-10 15:52:23.000000000 +09:00
+    gps1_pka2+7033c93adba70e063c3b744929e6f7c8:
       name: gps1_pka2
       rate: 0
       win: 3.18814600262029
       loss: 4.78618461567772
       rating_group: 999
-      last_modified: 2008-02-12 15:54:28 +09:00
-    k+9fe9de3be8ad533149a36f366dff0bb3: 
+      last_modified: 2008-02-12 15:54:28.000000000 +09:00
+    k+9fe9de3be8ad533149a36f366dff0bb3:
       name: k
       rate: 0
       win: 1.34444228366597
       loss: 0.448143453067201
       rating_group: 999
-      last_modified: 2008-02-22 12:20:16 +09:00
-    pc2+0cc175b9c0f1b6a831c399e269772661: 
+      last_modified: 2008-02-22 12:20:16.000000000 +09:00
+    pc2+0cc175b9c0f1b6a831c399e269772661:
       name: pc2
       rate: 0
       win: 2.76296190816758
       loss: 1.79764425753254
       rating_group: 999
-      last_modified: 2008-04-25 19:33:00 +09:00
-    gps_pp6+be1cf926449472274af55a1b074e357e: 
+      last_modified: 2008-04-25 19:33:00.000000000 +09:00
+    gps_pp6+be1cf926449472274af55a1b074e357e:
       name: gps_pp6
       rate: 0
       win: 4.0
       loss: 6.0
       rating_group: 999
-      last_modified: 2008-05-08 23:31:31 +09:00
-    gps6_pw5+d22cb490b411ace707b146b090d1a2be: 
+      last_modified: 2008-05-08 23:31:31.000000000 +09:00
+    gps6_pw5+d22cb490b411ace707b146b090d1a2be:
       name: gps6_pw5
       rate: 0
       win: 1.0
       loss: 0.0
       rating_group: 999
-      last_modified: 2008-05-08 00:03:24 +09:00
-    gps_mc0+aa6598cc8577f5af6c122e18d13efb40: 
+      last_modified: 2008-05-08 00:03:24.000000000 +09:00
+    gps_mc0+aa6598cc8577f5af6c122e18d13efb40:
       name: gps_mc0
       rate: 0
       win: 4.65735073577001
       loss: 3.88433998290132
       rating_group: 999
-      last_modified: 2008-04-10 05:52:07 +09:00
-  4: 
-    gps6_orig+23daece4324fd5c2c7f2ef3f01e22cbd: 
+      last_modified: 2008-04-10 05:52:07.000000000 +09:00
+  4:
+    gps6_orig+23daece4324fd5c2c7f2ef3f01e22cbd:
       name: gps6_orig
       rate: 1005.0
       win: 56.4475550891671
       loss: 52.9404587900779
       rating_group: 4
-      last_modified: 2008-04-25 22:11:02 +09:00
-    gps8_orig+04b3be38b45d6c7341216df4494eba88: 
+      last_modified: 2008-04-25 22:11:02.000000000 +09:00
+    gps8_orig+04b3be38b45d6c7341216df4494eba88:
       name: gps8_orig
       rate: 988.0
       win: 34.8334553178621
       loss: 34.7756725880529
       rating_group: 4
-      last_modified: 2008-04-21 01:54:49 +09:00
-    gps7_nmb005+0603aa6be69954719efd16294d46e1fd: 
+      last_modified: 2008-04-21 01:54:49.000000000 +09:00
+    gps7_nmb005+0603aa6be69954719efd16294d46e1fd:
       name: gps7_nmb005
       rate: 1023.0
       win: 19.0187875399771
       loss: 15.5574290158712
       rating_group: 4
-      last_modified: 2008-04-19 22:30:16 +09:00
-    gps7_nmbf2048+7222b303fe6c918f085352fae3e948e0: 
+      last_modified: 2008-04-19 22:30:16.000000000 +09:00
+    gps7_nmbf2048+7222b303fe6c918f085352fae3e948e0:
       name: gps7_nmbf2048
       rate: 1023.0
       win: 19.1988151416004
       loss: 17.3554541281629
       rating_group: 4
-      last_modified: 2008-04-24 18:07:39 +09:00
-    gps7_nmb005_2+f9f5b4ad8876211ec87063448e3f309c: 
+      last_modified: 2008-04-24 18:07:39.000000000 +09:00
+    gps7_nmb005_2+f9f5b4ad8876211ec87063448e3f309c:
       name: gps7_nmb005_2
       rate: 953.0
       win: 30.9780397575928
       loss: 39.830690034666
       rating_group: 4
-      last_modified: 2008-04-22 21:18:36 +09:00
-    gps7_nmb005_3+833dbce4e46df7d07021364f70b004be: 
+      last_modified: 2008-04-22 21:18:36.000000000 +09:00
+    gps7_nmb005_3+833dbce4e46df7d07021364f70b004be:
       name: gps7_nmb005_3
       rate: 1005.0
       win: 18.5204889389606
       loss: 18.5374372283291
       rating_group: 4
-      last_modified: 2008-04-25 22:11:02 +09:00
-  10: 
-    gps7_kab3+b2920e23a50211cb5e3cd14f65efd909: 
+      last_modified: 2008-04-25 22:11:02.000000000 +09:00
+  10:
+    gps7_kab3+b2920e23a50211cb5e3cd14f65efd909:
       name: gps7_kab3
       rate: 1076.0
       win: 12.0
       loss: 7.0
       rating_group: 10
-      last_modified: 2008-05-03 06:30:07 +09:00
-    gps7_kab5+b58d115ca7a38174b8e094d80d1f754b: 
+      last_modified: 2008-05-03 06:30:07.000000000 +09:00
+    gps7_kab5+b58d115ca7a38174b8e094d80d1f754b:
       name: gps7_kab5
       rate: 1052.0
       win: 12.0
       loss: 8.0
       rating_group: 10
-      last_modified: 2008-05-04 17:13:22 +09:00
-    gps7_kab4+dadcdaa4377a9741d4476298f0dc3d28: 
+      last_modified: 2008-05-04 17:13:22.000000000 +09:00
+    gps7_kab4+dadcdaa4377a9741d4476298f0dc3d28:
       name: gps7_kab4
       rate: 888.0
       win: 7.0
       loss: 12.0
       rating_group: 10
-      last_modified: 2008-05-03 23:35:23 +09:00
-    gps7+3b3309e4846a69406950c38040488e08: 
+      last_modified: 2008-05-03 23:35:23.000000000 +09:00
+    gps7+3b3309e4846a69406950c38040488e08:
       name: gps7
       rate: 982.0
       win: 27.0
       loss: 31.0
       rating_group: 10
-      last_modified: 2008-05-04 17:13:22 +09:00
+      last_modified: 2008-05-04 17:13:22.000000000 +09:00
index da94d50..348ca42 100644 (file)
@@ -1,3 +1,2 @@
---- 
+---
 players: {}
-
index bde5691..8cc1109 100755 (executable)
@@ -4,7 +4,7 @@
 # This program corrects illegal lines introduced by the #14635 bug.
 #
 # Author::    Daigo Moriwaki <daigo at debian dot org>
-# Copyright:: Copyright (C) 2008  Daigo Moriwaki <daigo at debian dot org>
+# Copyright:: Copyright (C) 2008-2012  Daigo Moriwaki <daigo at debian dot org>
 #
 # $Id$
 #
index b393bcd..6c29bbd 100755 (executable)
@@ -5,7 +5,7 @@
 # you will see such files under the some_dir directory.
 #
 # Author::    Daigo Moriwaki <daigo at debian dot org>
-# Copyright:: Copyright (C) 2006-2008  Daigo Moriwaki <daigo at debian dot org>
+# Copyright:: Copyright (C) 2006-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # $Id$
 #
index fbf42fe..64a5ea6 100755 (executable)
@@ -8,7 +8,7 @@
 #   * On Debian, $ sudo apt-get install gnuplot
 #
 # Author::    Daigo Moriwaki <daigo at debian dot org>
-# Copyright:: Copyright (C) 2006-2008  Daigo Moriwaki <daigo at debian dot org>
+# Copyright:: Copyright (C) 2006-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # $Id$
 #
index 115fc0c..32a9456 100755 (executable)
@@ -9,7 +9,7 @@
 #      - Gnuplot:  http://www.gnuplot.info/
 #                  On Debian, $ sudo apt-get install gnuplot
 #    
-#    Copyright (C) 2008  Daigo Moriwaki <daigo@debian.org>
+#    Copyright (C) 2008-2012 Daigo Moriwaki <daigo@debian.org>
 #
 #    Version: $Id$
 #
index 8c990b8..568758f 100755 (executable)
@@ -10,7 +10,7 @@
 #   $ ./statistics.rb /dev/shm/floodgate
 #
 # Author::    Daigo Moriwaki <daigo at debian dot org>
-# Copyright:: Copyright (C) 2009  Daigo Moriwaki <daigo at debian dot org>
+# Copyright:: Copyright (C) 2009-2012 Daigo Moriwaki <daigo at debian dot org>
 #
 # $Id$
 #
index edaf51e..97f8059 100755 (executable)
--- a/webserver
+++ b/webserver
@@ -1,6 +1,6 @@
-#!/usr/bin/ruby
+#!/usr/bin/ruby1.9.1
 
-## Copyright (C) 2007 Daigo Moriwaki <daigo at debian dot org>
+## Copyright (C) 2007-2012 Daigo Moriwaki <daigo at debian dot org>
 ##
 ## This program is free software; you can redistribute it and/or modify
 ## it under the terms of the GNU General Public License as published by