OSDN Git Service

Merge branch '201410-maxmoves'
authorDaigo Moriwaki <daigo@debian.org>
Sat, 17 Jan 2015 01:47:58 +0000 (10:47 +0900)
committerDaigo Moriwaki <daigo@debian.org>
Sat, 17 Jan 2015 01:47:58 +0000 (10:47 +0900)
Conflicts:
changelog
shogi_server.rb

19 files changed:
README
changelog
shogi-server
shogi_server.rb
shogi_server/board.rb
shogi_server/game.rb
shogi_server/game_result.rb
shogi_server/time_clock.rb
test/TC_ALL.rb
test/TC_board.rb
test/TC_fork.rb
test/TC_functional.rb
test/TC_game.rb
test/TC_game_least_0.rb [new file with mode: 0644]
test/TC_jishogi_kachi.rb
test/TC_max_moves_draw.rb [new file with mode: 0644]
test/TC_time_clock.rb
test/baseclient.rb
test/csa/max_moves_draw.csa [new file with mode: 0644]

diff --git a/README b/README
index b746456..774d0c5 100644 (file)
--- a/README
+++ b/README
@@ -4,48 +4,41 @@ The Shogi-server project develops Shogi-server, a rating tool and so on.
 
 == Shogi-server
 
-Shogi-server is a server that implements the Server Protocol Ver 1.1 defined
+Shogi-server is a server that implements the Server Protocol Ver 1.2.1 defined
 by Computer Shogi Association (CSA[http://www.computer-shogi.org/index_e.html]) 
 in order for computer shogi players to play games.   
 
 === Pre-requires
 
-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. 
+Ruby 2.1 or later
 
 For Debian,
- $ 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.
+  $ sudo aptitude install ruby
 
 === Install
 
- $ git clone git://git.sourceforge.jp/gitroot/shogi-server/shogi-server.git
 $ git clone git://git.sourceforge.jp/gitroot/shogi-server/shogi-server.git
 
 The following files are required to run Shogi-server:
 
-- shogi-server
-- shogi_server.rb
-- shogi_server/**/*.rb
+  - shogi-server
+  - shogi_server.rb
+  - shogi_server/**/*.rb
 
 === Run
 
 Examples:
 
- $ ./shogi-server hoge 4000
+Run the server with CSA Protocol V1.2 or later
+
+  $ ./shogi-server hoge 4000
+
+With CSA Protocol V1.1.2 or before
 
$ ruby1.8 ./shogi-server hoge 4000
 $ ./shogi-server --max-moves 0 --least-time-per-move 1 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
+See others written in the 'shogi-server' file.
 
 == Other tools
 
@@ -69,14 +62,12 @@ Run test cases
 
 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
-
+- ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin13]
+  Finished in 55.025733 seconds.
+  383 tests, 1370 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
+  100% passed
+  6.96 tests/s, 24.90 assertions/s
+  ruby TC_ALL.rb  1.97s user 0.34s system 4% cpu 55.424 total
   
 ---
-2012-01-07 Daigo Moriwaki <daigo at debian dot org>
+2015-01-17  Daigo Moriwaki <daigo at debian dot org>
index 95af1ef..bdd04c4 100644 (file)
--- a/changelog
+++ b/changelog
@@ -1,3 +1,9 @@
+2015-01-12  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi-server]
+         - shogi_server.rb: Follow an API change in a upstream class:
+           LogDevice.previous_period_end
+
 2014-12-27  Daigo Moriwaki <daigo at debian dot org>
 
        * [shogi-server]
              'black_rate:Test_sente+275876e34cf609db118f3d84b799a790:2763.0
              'white_rate:Test_gote+275876e34cf609db118f3d84b799a790:2345.0
 
+2014-10-12  Daigo Moriwaki <daigo at debian dot org>
+
+       * [shogi_server]
+         - New feature: max moves
+           - New command line option: --max-moves n
+             When a game with the n-th move played does not end, make the
+             game a draw (default 256 in compliance with CSA Protocol V1.2
+             or later).  Setting 0 disables this feature for
+             CSA Protocol V1.1.2 or before.
+           - Players will receive a new message, "#MAX_MOVES", upon an end
+             of such a game:
+               #MAX_MOVES
+               #CENSORED
+           - A new log summary type, "max_moves", has been assigned for games
+             drawing with max moves.
+             'summary:max_moves:name_sente draw:name_gote draw
+         - Least time per move:
+           - New command line option: --least-time-per-move n
+             This option specifies a least time in second per move, which
+             is 0 second by default, meaning that a decimal
+             fraction of time for a move will be truncated in compliance
+             with CSA Protocol V1.2 or later.
+             Set 1 for CSA Protocol V1.1.2 or before.
+
 2014-07-19  Daigo Moriwaki <daigo at debian dot org>
 
        * [mk_rate]
index d959b4f..8073889 100755 (executable)
@@ -78,6 +78,13 @@ OPTIONS
         port_number
                 a port number for the server to listen. 
                 4081 is often used.
+        --least-time-per-move n
+                Least time in second per move: 0, 1 (default 1).
+                  - 0: The new rule that CSA introduced in November 2014.
+                  - 1: The old rule before it.
+        --max-moves n
+                when a game with the n-th move played does not end, make the game a draw.
+                Default 256. 0 disables this feature.
         --pid-file file
                 a file path in which a process ID will be written.
                 Use with --daemon option.
@@ -95,14 +102,17 @@ EXAMPLES
            Run the shogi-server. Then clients can connect to port#4081.
            The server output logs to the stdout.
 
-        2. % ./shogi-server --daemon . --pid-file ./shogi-server.pid \
+        2. % ./shogi-server --max-moves 0 --least-time-per-move 1 test 4081
+           Run the shogi-server in compliance with CSA Protocol V1.1.2 or before.
+
+        3. % ./shogi-server --daemon . --pid-file ./shogi-server.pid \
                             --player-log-dir ./player-logs \
                             test 4081
            Run the shogi-server as a daemon. The server outputs regular logs
            to shogi-server.log located in the current directory and network 
            messages in ./player-logs directory.
 
-        3. % ./shogi-server --daemon . --pid-file ./shogi-server.pid \
+        4. % ./shogi-server --daemon . --pid-file ./shogi-server.pid \
                             --player-log-dir ./player-logs \
                             --floodgate-games floodgate-900-0,floodgate-3600-0 \
                             test 4081
@@ -193,10 +203,12 @@ end
 def parse_command_line
   options = Hash::new
   parser = GetoptLong.new(
-    ["--daemon",            GetoptLong::REQUIRED_ARGUMENT],
-    ["--floodgate-games",   GetoptLong::REQUIRED_ARGUMENT],
-    ["--pid-file",          GetoptLong::REQUIRED_ARGUMENT],
-    ["--player-log-dir",    GetoptLong::REQUIRED_ARGUMENT])
+    ["--daemon",              GetoptLong::REQUIRED_ARGUMENT],
+    ["--floodgate-games",     GetoptLong::REQUIRED_ARGUMENT],
+    ["--least-time-per-move", GetoptLong::REQUIRED_ARGUMENT],
+    ["--max-moves",           GetoptLong::REQUIRED_ARGUMENT],
+    ["--pid-file",            GetoptLong::REQUIRED_ARGUMENT],
+    ["--player-log-dir",      GetoptLong::REQUIRED_ARGUMENT])
   parser.quiet = true
   begin
     parser.each_option do |name, arg|
@@ -265,6 +277,12 @@ def check_command_line
     $stderr.puts "WARNING: --floodgate-history has been deprecated."
     $options["floodgate-history"] = nil
   end
+
+  $options["max-moves"] ||= 256
+  $options["max-moves"] = $options["max-moves"].to_i
+
+  $options["least-time-per-move"] ||= 0
+  $options["least-time-per-move"] = $options["least-time-per-move"].to_i
 end
 
 # See if a file can be created in the directory.
index 82c83b1..490249c 100644 (file)
@@ -49,9 +49,8 @@ Max_Identifier_Length = 32
 Default_Timeout = 60            # for single socket operation
 Default_Game_Name = "default-1500-0"
 One_Time = 10
-Least_Time_Per_Move = 1
 Login_Time = 300                # time for LOGIN
-Revision = "20140107"
+Revision = "20150117"
 
 RELOAD_FILES = ["shogi_server/league/floodgate.rb",
                 "shogi_server/league/persistent.rb",
@@ -85,7 +84,11 @@ class Logger < ::Logger
       end
 
       def age_file_name(time)
-        postfix = previous_period_end(time).strftime("%Y%m%d") # YYYYMMDD
+        if RUBY_VERSION >= "2.2.0"
+          postfix = previous_period_end(time, @shift_age).strftime("%Y%m%d")   # YYYYMMDD
+        else
+          postfix = previous_period_end(time).strftime("%Y%m%d")       # YYYYMMDD
+        end
         age_file = File.join(
                      File.dirname(@filename),
                      postfix[0..3], # YYYY
index 66d4d01..bcf8887 100644 (file)
@@ -626,6 +626,7 @@ EOF
   #   - :uchifuzume 
   #   - :oute_kaihimore 
   #   - (:outori will not be returned)
+  #   - :max_moves
   #
   def handle_one_move(str, sente=nil)
     if (str =~ /^([\+\-])(\d)(\d)(\d)(\d)([A-Z]{2})/)
@@ -713,6 +714,14 @@ EOF
       return :sennichite 
     end
 
+    # New rule that CSA introduced in November 2014.
+    # If a game with 256 plies does not end, make the game a draw.
+    # When running test cases $options might be nil.
+    if $options && $options["max-moves"] &&
+       $options["max-moves"] > 0 && @move_count >= $options["max-moves"]
+      return :max_moves
+    end
+
     return :normal
   end
 
index 50bdbaa..a43b752 100644 (file)
@@ -71,7 +71,7 @@ class Game
       @total_time = $1.to_i
       @byoyomi = $2.to_i
 
-      @time_clock = TimeClock::factory(Least_Time_Per_Move, @game_name)
+      @time_clock = TimeClock::factory($options["least-time-per-move"], @game_name)
     end
 
     if (player0.sente)
@@ -292,6 +292,8 @@ class Game
     elsif (move_status == :oute_kaihimore)
       # the current player losed
       @result = GameResultOuteKaihiMoreWin.new(self, @next_player, @current_player)
+    elsif (move_status == :max_moves)
+      @result = GameResultMaxMovesDraw.new(self, @current_player, @next_player)
     else
       finish_flag = false
     end
@@ -373,7 +375,7 @@ BEGIN Time
 Time_Unit:#{@time_clock.time_unit}
 Total_Time:#{@total_time}
 Byoyomi:#{@byoyomi}
-Least_Time_Per_Move:#{Least_Time_Per_Move}
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 Remaining_Time+:#{@sente.mytime}
 Remaining_Time-:#{@gote.mytime}
 Last_Move:#{@last_move}
@@ -407,7 +409,7 @@ BEGIN Time
 Time_Unit:#{@time_clock.time_unit}
 Total_Time:#{@total_time}
 Byoyomi:#{@byoyomi}
-Least_Time_Per_Move:#{Least_Time_Per_Move}
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 #{@board.initial_string.chomp}
index a90289d..678ef3f 100644 (file)
@@ -343,4 +343,21 @@ class GameResultSennichiteDraw < GameResultDraw
   end
 end
 
+class GameResultMaxMovesDraw < GameResultDraw
+  def initialize(game, winner, loser)
+    super
+    @log_summary_type = "max_moves"
+    @result_type      = "#MAX_MOVES"
+  end
+
+  def process
+    @players.each do |player|
+      player.write_safe("#MAX_MOVES\n#CENSORED\n")
+    end
+    # no log
+    log_summary
+    notify
+  end
+end
+
 end # ShogiServer
index 6426fda..52a747d 100644 (file)
@@ -36,7 +36,11 @@ class TimeClock
     if (byoyomi_str == "060")
       @time_clock = StopWatchClock.new(least_time_per_move, total_time, byoyomi)
     else
-      @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
+      if least_time_per_move == 0
+        @time_clock = ChessClockWithLeastZero.new(least_time_per_move, total_time, byoyomi)
+      else
+        @time_clock = ChessClock.new(least_time_per_move, total_time, byoyomi)
+      end
     end
   end
 
@@ -48,7 +52,7 @@ class TimeClock
 
   # Returns thinking time duration
   #
-  def time_duration(start_time, end_time)
+  def time_duration(mytime, start_time, end_time)
     # implement this
     return 9999999
   end
@@ -69,7 +73,7 @@ class TimeClock
   # Updates a player's remaining time and returns thinking time.
   #
   def process_time(player, start_time, end_time)
-    t = time_duration(start_time, end_time)
+    t = time_duration(player.mytime, start_time, end_time)
     
     player.mytime -= t
     if (player.mytime < 0)
@@ -87,12 +91,12 @@ class ChessClock < TimeClock
     super
   end
 
-  def time_duration(start_time, end_time)
+  def time_duration(mytime, start_time, end_time)
     return [(end_time - start_time).floor, @least_time_per_move].max
   end
 
   def timeout?(player, start_time, end_time)
-    t = time_duration(start_time, end_time)
+    t = time_duration(player.mytime, start_time, end_time)
 
     if ((player.mytime - t <= -@byoyomi) && 
         ((@total_time > 0) || (@byoyomi > 0)))
@@ -107,6 +111,30 @@ class ChessClock < TimeClock
   end
 end
 
+# Calculates thinking time with chess clock, truncating decimal seconds for
+# thinking time. This is a new rule that CSA introduced in November 2014.
+#
+# least_time_per_move should be 0.
+# byoyomi should be more than 0.
+#
+class ChessClockWithLeastZero < ChessClock
+  def initialize(least_time_per_move, total_time, byoyomi)
+    if least_time_per_move != 0
+      raise ArgumentError, "least_time_per_move #{least_time_per_move} should be 0."
+    end
+    super
+  end
+
+  def time_duration(mytime, start_time, end_time)
+    t = end_time - start_time
+    return t.floor
+  end
+
+  def to_s
+    return "ChessClockWithLeastZero: LeastTimePerMove %d; TotalTime %d; Byoyomi %d" % [@least_time_per_move, @total_time, @byoyomi]
+  end
+end
+
 class StopWatchClock < TimeClock
   def initialize(least_time_per_move, total_time, byoyomi)
     super
@@ -116,13 +144,13 @@ class StopWatchClock < TimeClock
     return "1min"
   end
 
-  def time_duration(start_time, end_time)
+  def time_duration(mytime, start_time, end_time)
     t = [(end_time - start_time).floor, @least_time_per_move].max
     return (t / @byoyomi) * @byoyomi
   end
 
   def timeout?(player, start_time, end_time)
-    t = time_duration(start_time, end_time)
+    t = time_duration(player.mytime, start_time, end_time)
 
     if (player.mytime <= t)
       return true
index d82277d..256a0cc 100644 (file)
@@ -13,9 +13,12 @@ require 'TC_floodgate_thread.rb'
 require 'TC_fork'
 require 'TC_functional'
 require 'TC_game'
+require 'TC_game_least_0'
 require 'TC_game_result'
 require 'TC_handicapped_boards'
-require 'TC_jishogi_kachi'
+# This game has more thatn 256 moves.
+# Disableing max-moves, "./shogi-server --max moves 0", is required.
+#require 'TC_jishogi_kachi'
 require 'TC_league'
 require 'TC_logger'
 require 'TC_login'
index b9d54fc..06e4efe 100644 (file)
@@ -24,24 +24,6 @@ EOM
     assert_equal(true, b.good_kachi?(false))
   end
 
-  def test_kachi_good
-    b = ShogiServer::Board.new
-    b.set_from_str(<<EOM)
-P1+HI+HI+KA+KA+OU *  *  *  * 
-P2+FU+FU+FU+FU+FU+FU *  *  * 
-P+00FU00FU
-EOM
-    assert_equal(true, b.good_kachi?(true))
-
-    b = ShogiServer::Board.new
-    b.set_from_str(<<EOM)
-P8-HI-HI-KA-KA-OU *  *  *  * 
-P9-FU-FU-FU-FU-FU-FU *  *  * 
-P-00FU
-EOM
-    assert_equal(true, b.good_kachi?(false))
-  end
-
   def test_kachi_bad
     b = ShogiServer::Board.new
     b.set_from_str(<<EOM)
index b788fd1..cfdf9e1 100644 (file)
@@ -16,8 +16,11 @@ class TestFork < BaseClient
   def test_wrong_game
     @admin = SocketPlayer.new "dummy", "admin", false
     @admin.connect
+    sleep 0.1
     @admin.reader
+    sleep 0.1
     @admin.login
+    sleep 0.1
 
     result, result2 = handshake do
       @admin.puts "%%FORK wronggame-900-0 buoy_WrongGame-900-0"
@@ -31,8 +34,11 @@ class TestFork < BaseClient
   def test_too_short_fork
     @admin = SocketPlayer.new "dummy", "admin", false
     @admin.connect
+    sleep 0.1
     @admin.reader
+    sleep 0.1
     @admin.login
+    sleep 0.1
 
     result, result2 = handshake do
       source_game = parse_game_name(@admin)
@@ -49,8 +55,12 @@ class TestFork < BaseClient
     
     @admin = SocketPlayer.new "dummy", "admin", "*"
     @admin.connect
+    sleep 0.1
     @admin.reader
+    sleep 0.1
     @admin.login
+    sleep 0.1
+
     assert buoy.is_new_game?("buoy_Fork-1500-0")
 
     result, result2 = handshake do
@@ -63,26 +73,34 @@ class TestFork < BaseClient
     @p1 = SocketPlayer.new "buoy_Fork", "p1", true
     @p2 = SocketPlayer.new "buoy_Fork", "p2", false
     @p1.connect
+    sleep 0.1
     @p2.connect
+    sleep 0.1
     @p1.reader
+    sleep 0.1
     @p2.reader
+    sleep 0.1
     @p1.login
+    sleep 0.1
     @p2.login
-    sleep 1
+    sleep 0.1
     @p1.game
+    sleep 0.1
     @p2.game
-    sleep 1
     @p1.agree
+    sleep 0.1
     @p2.agree
-    sleep 1
+    sleep 0.1
     assert /^Total_Time:1500/ =~ @p1.message
     assert /^Total_Time:1500/ =~ @p2.message
     @p2.move("-3334FU")
-    sleep 1
+    sleep 0.1
     @p1.toryo
-    sleep 1
+    sleep 0.1
     @p2.logout
+    sleep 0.1
     @p1.logout
+    sleep 0.1
 
     @admin.logout
   end
@@ -92,8 +110,11 @@ class TestFork < BaseClient
     
     @admin = SocketPlayer.new "dummy", "admin", "*"
     @admin.connect
+    sleep 0.1
     @admin.reader
+    sleep 0.1
     @admin.login
+    sleep 0.1
 
     result, result2 = handshake do
       source_game = parse_game_name(@admin)
@@ -106,26 +127,35 @@ class TestFork < BaseClient
     @p1 = SocketPlayer.new "buoy_TestFork_1", "p1", true
     @p2 = SocketPlayer.new "buoy_TestFork_1", "p2", false
     @p1.connect
+    sleep 0.1
     @p2.connect
+    sleep 0.1
     @p1.reader
+    sleep 0.1
     @p2.reader
+    sleep 0.1
     @p1.login
+    sleep 0.1
     @p2.login
-    sleep 1
+    sleep 0.1
     @p1.game
+    sleep 0.1
     @p2.game
-    sleep 1
+    sleep 0.1
     @p1.agree
+    sleep 0.1
     @p2.agree
-    sleep 1
+    sleep 0.1
     assert /^Total_Time:1500/ =~ @p1.message
     assert /^Total_Time:1500/ =~ @p2.message
     @p2.move("-3334FU")
-    sleep 1
+    sleep 0.1
     @p1.toryo
-    sleep 1
+    sleep 0.1
     @p2.logout
+    sleep 0.1
     @p1.logout
+    sleep 0.1
 
     @admin.logout
   end
index 51aca58..7f8d884 100644 (file)
@@ -48,9 +48,9 @@ P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
 +
 'rating:atmark_B@p1+275876e34cf609db118f3d84b799a790:atmark_W@p2+275876e34cf609db118f3d84b799a790
 +2726FU
-T1
+T0
 -3334FU
-T1
+T0
 %TORYO
 'P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
 'P2 * -HI *  *  *  *  * -KA * 
@@ -115,9 +115,9 @@ P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
 +
 'rating:hc2p_hoge_B+275876e34cf609db118f3d84b799a790:hc2p_hoge_W+275876e34cf609db118f3d84b799a790
 +2726FU
-T1
+T0
 -3334FU
-T1
+T0
 %TORYO
 'P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
 'P2 * -HI *  *  *  *  * -KA * 
index 8d7d493..08ffcf2 100644 (file)
@@ -5,6 +5,9 @@ require 'shogi_server/board'
 require 'shogi_server/game'
 require 'shogi_server/player'
 
+$options = {}
+$options["least-time-per-move"] = 1
+
 def log_message(str)
   $stderr.puts str
 end
@@ -52,7 +55,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -86,7 +89,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -154,7 +157,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -189,7 +192,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -261,7 +264,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
@@ -297,7 +300,7 @@ BEGIN Time
 Time_Unit:1sec
 Total_Time:1500
 Byoyomi:0
-Least_Time_Per_Move:1
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
 END Time
 BEGIN Position
 P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
diff --git a/test/TC_game_least_0.rb b/test/TC_game_least_0.rb
new file mode 100644 (file)
index 0000000..3429f07
--- /dev/null
@@ -0,0 +1,411 @@
+$:.unshift File.join(File.dirname(__FILE__), "..")
+require 'test/unit'
+require 'test/mock_player'
+require 'shogi_server/board'
+require 'shogi_server/game'
+require 'shogi_server/player'
+
+$options = {}
+$options["least-time-per-move"] = 0
+
+def log_message(str)
+  $stderr.puts str
+end
+
+def log_warning(str)
+  $stderr.puts str
+end
+
+def log_error(str)
+  $stderr.puts str
+end
+
+$league = ShogiServer::League.new(File.dirname(__FILE__))
+$league.event = "test"
+
+class TestGameWithLeastZero < Test::Unit::TestCase
+
+  def test_new
+    game_name = "hoge-1500-10"
+    board = ShogiServer::Board.new
+    board.initial
+    p1 = MockPlayer.new
+    p1.sente = true
+    p1.name  = "p1"
+    p2 = MockPlayer.new
+    p2.sente = false
+    p2.name  = "p2"
+    
+    game = ShogiServer::Game.new game_name, p1, p2, board 
+    assert_equal "", game.last_move
+
+    p1_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:+
+Rematch_On_Draw:NO
+To_Move:+
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+END Position
+END Game_Summary
+EOF
+    assert_equal(p1_out, p1.out.first)
+
+    p2_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:-
+Rematch_On_Draw:NO
+To_Move:+
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+END Position
+END Game_Summary
+EOF
+    assert_equal(p2_out, p2.out.first)
+
+    file = Pathname.new(game.logfile)
+    log = file.read
+    assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
+V2
+N+p1
+N-p2
+$EVENT:#{game.game_id}
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+EOF
+  end
+
+  def test_new_buoy_1_move
+    game_name = "buoyhoge-1500-10"
+    board = ShogiServer::Board.new
+    board.set_from_moves ["+7776FU"]
+    p1 = MockPlayer.new
+    p1.sente = true
+    p1.name  = "p1"
+    p2 = MockPlayer.new
+    p2.sente = false
+    p2.name  = "p2"
+    
+    game = ShogiServer::Game.new game_name, p1, p2, board 
+    assert_equal "+7776FU,T1", game.last_move
+
+    p1_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:+
+Rematch_On_Draw:NO
+To_Move:-
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
++7776FU,T1
+END Position
+END Game_Summary
+EOF
+    assert_equal(p1_out, p1.out.first)
+
+    p2_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:-
+Rematch_On_Draw:NO
+To_Move:-
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
++7776FU,T1
+END Position
+END Game_Summary
+EOF
+    assert_equal(p2_out, p2.out.first)
+
+    file = Pathname.new(game.logfile)
+    log = file.read
+    assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
+V2
+N+p1
+N-p2
+$EVENT:#{game.game_id}
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+'buoy game starting with 1 moves
++7776FU
+T1
+EOF
+  end
+
+  def test_new_buoy_2_moves
+    game_name = "buoyhoge-1500-10"
+    board = ShogiServer::Board.new
+    board.set_from_moves ["+7776FU", "-3334FU"]
+    p1 = MockPlayer.new
+    p1.sente = true
+    p1.name  = "p1"
+    p2 = MockPlayer.new
+    p2.sente = false
+    p2.name  = "p2"
+    
+    game = ShogiServer::Game.new game_name, p1, p2, board 
+    assert_equal "-3334FU,T1", game.last_move
+
+    p1_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:+
+Rematch_On_Draw:NO
+To_Move:+
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
++7776FU,T1
+-3334FU,T1
+END Position
+END Game_Summary
+EOF
+    assert_equal(p1_out, p1.out.first)
+
+    p2_out = <<EOF
+BEGIN Game_Summary
+Protocol_Version:1.1
+Protocol_Mode:Server
+Format:Shogi 1.0
+Declaration:Jishogi 1.1
+Game_ID:#{game.game_id}
+Name+:p1
+Name-:p2
+Your_Turn:-
+Rematch_On_Draw:NO
+To_Move:+
+BEGIN Time
+Time_Unit:1sec
+Total_Time:1500
+Byoyomi:10
+Least_Time_Per_Move:#{$options["least-time-per-move"]}
+END Time
+BEGIN Position
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
++7776FU,T1
+-3334FU,T1
+END Position
+END Game_Summary
+EOF
+    assert_equal(p2_out, p2.out.first)
+
+    file = Pathname.new(game.logfile)
+    log = file.read
+    assert_equal(<<EOF, log.gsub(/^\$START_TIME.*?\n/,''))
+V2
+N+p1
+N-p2
+$EVENT:#{game.game_id}
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
+'buoy game starting with 2 moves
++7776FU
+T1
+-3334FU
+T1
+EOF
+  end
+  
+  def test_monitor_add
+    game_name = "hoge-1500-10"
+    board = ShogiServer::Board.new
+    board.initial
+    p1 = MockPlayer.new
+    p1.sente = true
+    p1.name  = "p1"
+    p2 = MockPlayer.new
+    p2.sente = false
+    p2.name  = "p2"
+    
+    game = ShogiServer::Game.new game_name, p1, p2, board 
+    handler1 = ShogiServer::MonitorHandler1.new p1
+    handler2 = ShogiServer::MonitorHandler2.new p2
+
+    assert_equal(0, game.monitors.size)
+    game.monitoron(handler1)
+    assert_equal(1, game.monitors.size)
+    game.monitoron(handler2)
+    assert_equal(2, game.monitors.size)
+    game.monitoroff(handler1)
+    assert_equal(1, game.monitors.size)
+    assert_equal(handler2, game.monitors.last)
+    game.monitoroff(handler2)
+    assert_equal(0, game.monitors.size)
+  end
+
+  def test_decide_turns
+    p1 = MockPlayer.new
+    p1.name = "p1"
+    p2 = MockPlayer.new
+    p2.name = "p2"
+
+    p1.sente=nil; p2.sente=false
+    ShogiServer::Game::decide_turns(p1, "+", p2)
+    assert_equal true, p1.sente
+
+    p1.sente=nil; p2.sente=nil
+    ShogiServer::Game::decide_turns(p1, "+", p2)
+    assert_equal true, p1.sente
+
+    p1.sente=nil; p2.sente=true
+    ShogiServer::Game::decide_turns(p1, "-", p2)
+    assert_equal false, p1.sente
+
+    p1.sente=nil; p2.sente=nil
+    ShogiServer::Game::decide_turns(p1, "-", p2)
+    assert_equal false, p1.sente
+
+    p1.sente=nil; p2.sente=false
+    ShogiServer::Game::decide_turns(p1, "*", p2)
+    assert_equal true, p1.sente
+
+    p1.sente=nil; p2.sente=true
+    ShogiServer::Game::decide_turns(p1, "*", p2)
+    assert_equal false, p1.sente
+
+    p1.sente=nil; p2.sente=nil
+    ShogiServer::Game::decide_turns(p1, "*", p2)
+    assert (p1.sente == true  && p2.sente == false) ||
+           (p1.sente == false && p2.sente == true)
+  end
+end
+
index 2d5242d..41c5e8a 100644 (file)
@@ -3,6 +3,9 @@ $topdir = File.expand_path File.dirname(__FILE__)
 require "test/baseclient"
 include Socket::Constants
 
+# This game has more thatn 256 moves.
+# Disableing max-moves, "./shogi-server --max moves 0", is required.
+
 class JishogiTest < ReadFileClient
   def test_jishogi_kachi
     csa = File.open(filepath("jishogi_kachi.csa")) {|f| f.read}
diff --git a/test/TC_max_moves_draw.rb b/test/TC_max_moves_draw.rb
new file mode 100644 (file)
index 0000000..cdb8f90
--- /dev/null
@@ -0,0 +1,18 @@
+$:.unshift File.join(File.dirname(__FILE__), "..")
+$topdir = File.expand_path File.dirname(__FILE__)
+require "test/baseclient"
+include Socket::Constants
+
+# This game has more thatn 256 moves.
+# Disableing max-moves, "./shogi-server --max moves 0", is required.
+
+class MaxMovesTest < ReadFileClient
+  def test_max_moves_draw
+    csa = File.open(filepath("max_moves_draw.csa")) {|f| f.read}
+    handshake(csa)
+    @p1.wait(/#MAX_MOVES\n#CENSORED/)
+    @p2.wait(/#MAX_MOVES\n#CENSORED/)
+    assert true
+    logout12
+  end
+end # Client class
index 151ba81..aa98ae7 100644 (file)
@@ -30,11 +30,11 @@ end
 class TestChessClock < Test::Unit::TestCase
   def test_time_duration
     tc = ShogiServer::ChessClock.new(1, 1500, 60)
-    assert_equal(1, tc.time_duration(100.1, 100.9))
-    assert_equal(1, tc.time_duration(100, 101))
-    assert_equal(1, tc.time_duration(100.1, 101.9))
-    assert_equal(2, tc.time_duration(100.1, 102.9))
-    assert_equal(2, tc.time_duration(100, 102))
+    assert_equal(1, tc.time_duration(nil, 100.1, 100.9))
+    assert_equal(1, tc.time_duration(nil, 100, 101))
+    assert_equal(1, tc.time_duration(nil, 100.1, 101.9))
+    assert_equal(2, tc.time_duration(nil, 100.1, 102.9))
+    assert_equal(2, tc.time_duration(nil, 100, 102))
   end
 
   def test_without_byoyomi
@@ -70,15 +70,56 @@ class TestChessClock < Test::Unit::TestCase
   end
 end
 
+class TestChessClockWithLeastZero < Test::Unit::TestCase
+  def test_time_duration_within_thinking_time
+    tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
+    assert_equal(0, tc.time_duration(100, 100.1, 100.9))  # 0.8
+    assert_equal(1, tc.time_duration(100, 100, 101))      # 1
+    assert_equal(1, tc.time_duration(100, 100.1, 101.9))  # 1.8
+    assert_equal(1, tc.time_duration(1,    100,   101))   # 1
+    assert_equal(2, tc.time_duration(100, 100.1, 102.9))  # 2.8
+    assert_equal(2, tc.time_duration(100, 100, 102))      # 2
+  end
+
+  def test_time_duration_over_thinking_time
+    tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
+    assert_equal(1, tc.time_duration(1,    100.1, 101.9))  # 1.8
+    assert_equal(2, tc.time_duration(2,    100.1, 102.9))  # 2.8
+  end
+
+  def test_with_byoyomi
+    tc = ShogiServer::ChessClockWithLeastZero.new(0, 900, 10)
+
+    p = DummyPlayer.new 100
+    assert(!tc.timeout?(p, 100, 101))    # 1
+    assert(!tc.timeout?(p, 100, 209))    # 109
+    assert(!tc.timeout?(p, 100, 209.9))  # 109.9
+    assert(tc.timeout?(p, 100, 210))     # 110
+    assert(tc.timeout?(p, 100, 210.1))   # 110.1
+    assert(tc.timeout?(p, 100, 211))     # 111
+  end
+
+  def test_with_byoyomi2
+    tc = ShogiServer::ChessClockWithLeastZero.new(0, 0, 10)
+
+    p = DummyPlayer.new 0
+    assert(!tc.timeout?(p, 100, 109))    # 9
+    assert(!tc.timeout?(p, 100, 109.9))  # 9.9
+    assert(tc.timeout?(p, 100, 110))     # 10
+    assert(tc.timeout?(p, 100, 110.1))   # 10.1
+    assert(tc.timeout?(p, 100, 110))     # 10.1
+  end
+end
+
 class TestStopWatchClock < Test::Unit::TestCase
   def test_time_duration
     tc = ShogiServer::StopWatchClock.new(1, 1500, 60)
-    assert_equal(0, tc.time_duration(100.1, 100.9))
-    assert_equal(0, tc.time_duration(100, 101))
-    assert_equal(0, tc.time_duration(100, 159.9))
-    assert_equal(60, tc.time_duration(100, 160))
-    assert_equal(60, tc.time_duration(100, 219))
-    assert_equal(120, tc.time_duration(100, 220))
+    assert_equal(0,   tc.time_duration(nil, 100.1, 100.9))
+    assert_equal(0,   tc.time_duration(nil, 100, 101))
+    assert_equal(0,   tc.time_duration(nil, 100, 159.9))
+    assert_equal(60,  tc.time_duration(nil, 100, 160))
+    assert_equal(60,  tc.time_duration(nil, 100, 219))
+    assert_equal(120, tc.time_duration(nil, 100, 220))
   end
 
   def test_with_byoyomi
index eafe62f..5be03b9 100644 (file)
@@ -182,20 +182,32 @@ class BaseClient < Test::Unit::TestCase
   end
 
   def login
+    sleep 0.1
     @p1.connect
+    sleep 0.1
     @p2.connect
+    sleep 0.1
     @p1.login
+    sleep 0.1
     @p2.login
+    sleep 0.1
     @p1.game
+    sleep 0.1
     @p2.game
+    sleep 0.1
     @p1.wait_game
+    sleep 0.1
     @p2.wait_game
   end
 
   def agree
+    sleep 0.1
     @p1.agree
+    sleep 0.1
     @p2.agree
+    sleep 0.1
     @p1.wait_agree
+    sleep 0.1
     @p2.wait_agree
   end
 
diff --git a/test/csa/max_moves_draw.csa b/test/csa/max_moves_draw.csa
new file mode 100644 (file)
index 0000000..70bfab5
--- /dev/null
@@ -0,0 +1,783 @@
+V2
+N+gps9_p
+N-gps8_pgsklp
+$EVENT:wdoor+pgsklp_32-0-30+gps9_p+gps8_pgsklp+20060428070035
+$START_TIME:2006/04/28 07:00:35
+P1-KY-KE-GI-KI-OU-KI-GI-KE-KY
+P2 * -HI *  *  *  *  * -KA * 
+P3-FU-FU-FU-FU-FU-FU-FU-FU-FU
+P4 *  *  *  *  *  *  *  *  * 
+P5 *  *  *  *  *  *  *  *  * 
+P6 *  *  *  *  *  *  *  *  * 
+P7+FU+FU+FU+FU+FU+FU+FU+FU+FU
+P8 * +KA *  *  *  *  * +HI * 
+P9+KY+KE+GI+KI+OU+KI+GI+KE+KY
++
++7776FU
+T2
+'** 0
+-8384FU
+T1
+'** 0
++7968GI
+T1
+'** 0
+-3334FU
+T1
+'** 0
++6766FU
+T1
+'** 0
+-7162GI
+T1
+'** 0
++5756FU
+T1
+'** 0
+-5354FU
+T1
+'** 0
++3948GI
+T1
+'** 0
+-3142GI
+T1
+'** 0
++4958KI
+T1
+'** 0
+-4132KI
+T1
+'** 0
++6978KI
+T1
+'** 0
+-5141OU
+T1
+'** 0
++5969OU
+T1
+'** 0
+-6152KI
+T1
+'** 0
++6877GI
+T1
+'** 0
+-4233GI
+T1
+'** 0
++8879KA
+T1
+'** 0
+-2231KA
+T1
+'** 0
++3736FU
+T1
+'** 0
+-4344FU
+T1
+'** 0
++5867KI
+T1
+'** 0
+-7374FU
+T1
+'** 0
++4837GI
+T1
+'** 0
+-3164KA
+T1
+'** 0
++7968KA
+T1
+'** 0
+-5243KI
+T1
+'** 0
++6979OU
+T1
+'** 0
+-4131OU
+T1
+'** 0
++2726FU
+T23
+'** 9 -3122OU +1716FU -6253GI +4746FU -9394FU +7988OU -8485FU +2625FU
+-3122OU
+T23
+'** 9 +7988OU -8173KE +2625FU -7385KE +7786GI -9394FU +4746FU -6473KA
++4746FU
+T24
+'** 0 -8173KE +7988OU -6442KA +2625FU -6364FU +1716FU -9394FU +7786GI
+-8173KE
+T24
+'** -28 +7988OU -6442KA +3748GI -6364FU +2937KE -6263GI +1716FU -9394FU
++1716FU
+T24
+'** 0 -9394FU +7988OU -9495FU +2625FU -6442KA +1615FU -8485FU %PASS
+-6442KA
+T11
+'** -31 +1615FU -6364FU +2625FU -6465FU +6665FU -7365KE +7766GI -0064FU
++1615FU
+T18
+'** -3 -6364FU +7988OU -6263GI +2625FU -8485FU +3726GI %PASS
+-6364FU
+T5
+'** -28 +2625FU -6465FU +6665FU %PASS
++2625FU
+T15
+'** -6 -9394FU +3726GI -6263GI +9796FU %PASS
+-6465FU
+T16
+'** -34 +6665FU %PASS
++6665FU
+T15
+'** 31 -8485FU +7766GI -9394FU +3726GI %PASS
+-9394FU
+T23
+'** -67 +6766KI -6263GI +3726GI -9495FU +7786GI -8485FU +8677GI -8252HI
++3726GI
+T1
+'** 34 %PASS
+-9495FU
+T23
+'** 156 +7766GI -8485FU +7988OU -6263GI %PASS
++6766KI
+T23
+'** 140 -9193KY +7675FU -6263GI +6857KA -9596FU +9796FU -8292HI +7786GI
+-9193KY
+T13
+'** 156 %PASS
++7675FU
+T23
+'** 137 -6263GI +6857KA -2231OU +7776GI -8292HI +7574FU -6374GI +0075FU
+-8292HI
+T1
+'** 165 +7969OU -6263GI +7776GI -8485FU +6979OU -7475FU +6675KI -9596FU
++8786FU
+T14
+'** 165 -6263GI +7776GI -4231KA +7574FU -6374GI +0075FU -7483GI
+-6263GI
+T18
+'** 187 +7776GI %PASS
++7776GI
+T6
+'** 187 -4231KA +7988OU -3142KA %PASS
+-4253KA
+T24
+'** 112 +7988OU -5342KA +7887KI -4253KA +7574FU -6374GI +0075FU -7483GI
++7988OU
+T25
+'** 206 %PASS
+-2231OU
+T1
+'** 228 +7887KI -5342KA +6857KA %PASS
++7574FU
+T22
+'** 253 -6374GI +0075FU -7463GI +7687GI -0074FU +6857KA -5342KA %PASS
+-6374GI
+T23
+'** 259 +0075FU -7463GI +5655FU -5455FU +6655KI -9596FU +9796FU -0098FU
++0075FU
+T1
+'** 153 -7483GI +5655FU -9596FU +9796FU -5455FU +6655KI -5342KA +7887KI
+-7463GI
+T25
+'** 256 +2937KE -0064FU +6564FU -5364KA +8685FU -9596FU +9796FU -7385KE
++7887KI
+T1
+'** 228 -3122OU +6857KA -0064FU +6564FU -5364KA +0065FU -6453KA +3635FU
+-0064FU
+T24
+'** 243 +6564FU -5364KA +0065FU -6453KA +8977KE -0064FU +6564FU -5364KA
++6564FU
+T23
+'** 268 -5364KA +2937KE -6442KA +6667KI -2324FU +2524FU -3324GI +0025FU
+-5364KA
+T1
+'** 379 +0065FU -6453KA +8977KE
++0065FU
+T22
+'** 71 -6442KA +8878OU -0074FU +7574FU -6374GI +0075FU -7463GI +6857KA
+-6453KA
+T1
+'** 231 +8977KE -0064FU +6564FU -5364KA +0065FU -6453KA +8878OU -0064FU
++6857KA
+T24
+'** 237 -3122OU +2818HI -1314FU +5768KA -1415FU +2615GI -1115KY +1815HI
+-3122OU
+T13
+'** 231 +3635FU -3435FU +8685FU -7385KE +0086FU -8597NK +8797KI -3334GI
++8977KE
+T23
+'** 221 -5342KA +8878OU -0064FU +6564FU -4264KA +0065FU -6453KA
+-0064FU
+T1
+'** 221 +6564FU -5364KA +8685FU -7385KE +7785KE -8485FU +0084FU -6372GI
++6564FU
+T19
+'** 203 -5364KA +0065FU -6442KA +2838HI -0074FU +7574FU -6374GI +0075FU
+-5364KA
+T1
+'** 409 +2848HI -6453KA +0065FU -0074FU +7574FU -6374GI +0075FU -7463GI
++8685FU
+T24
+'** 268 -7385KE +7785KE -8485FU +0084FU -8586FU +8786KI -9282HI +0083KE
+-8485FU
+T19
+'** 193 +0065FU -6431KA +7785KE -7385KE +7685GI %PASS
++0065FU
+T25
+'** 81 -6442KA +0084FU -9282HI +7785KE -7385KE +7685GI -0073KE +0074KE
+-6431KA
+T1
+'** 190 +7785KE -7385KE +7685GI -0083FU %PASS
++7785KE
+T22
+'** 215 -7385KE +7685GI -9282HI +0086FU -0084FU +8576GI -8292HI +8878OU
+-7385KE
+T1
+'** 275 +7685GI -9282HI +0086FU -0084FU +8576GI
++7685GI
+T23
+'** 194 -9282HI +0086FU -0084FU +8576GI -8292HI %PASS
+-9282HI
+T1
+'** 240 +0086FU -0084FU +8574GI -6374GI +7574FU -8485FU +0071GI -8272HI
++0086FU
+T23
+'** 181 -0084FU +8576GI -8292HI +0077KE -0073FU +8685FU -8485FU +7785KE
+-0084FU
+T1
+'** 212 +8574GI -6374GI +7574FU -8485FU +7473TO -8586FU +8777KI -0087GI
++8576GI
+T24
+'** 186 -3153KA +8878OU -8292HI +2818HI -1112KY +0067KE -0064FU +6564FU
+-0064FU
+T23
+'** 228 +6564FU -3164KA +7665GI -8485FU +8685FU -6453KA +6576GI -5364KA
++6564FU
+T23
+'** 207 -3164KA +7665GI -6442KA
+-6364GI
+T1
+'** 439 +7574FU -0065FU +7665GI -8485FU +8685FU -6465GI +6665KI -8285HI
++1917KY
+T23
+'** 209 -8292HI +2818HI %PASS
+-6473GI
+T15
+'** 296 +2818HI -3142KA +0065FU %PASS
++2818HI
+T23
+'** 268 -8292HI +3635FU -3435FU +0047KE -0064FU +4735KE -4353KI +0034FU
+-8262HI
+T24
+'** 282 +2937KE -6292HI +4645FU -4445FU +3745KE -3344GI +0046FU -7382GI
++1514FU
+T22
+'** 290 -1314FU +0065FU -3153KA +0013FU -1113KY %PASS
+-1314FU
+T23
+'** 153 %PASS
++0065FU
+T1
+'** 117 -3142KA +6667KI -6292HI +6777KI %PASS
+-6272HI
+T18
+'** 121 +0015FU -1415FU +2615GI -0014FU +1526GI %PASS
++2637GI
+T24
+'** 123 -0064FU +0026KE -3142KA +6564FU -7364GI +0065FU -6453GI %PASS
+-3153KA
+T1
+'** 172 +3748GI %PASS
++6667KI
+T22
+'** 228 -7292HI %PASS
+-0064FU
+T24
+'** 181 +0026KE -6465FU +7665GI -0064FU +6576GI -0065KE +5768KA -7292HI
++6777KI
+T17
+'** 181 -6465FU +7574FU -7374GI +5784KA -0075FU +7667GI -6566FU +6766GI
+-6465FU
+T24
+'** 120 +7574FU -7374GI +5784KA -0075FU +7667GI -0076KE +8878OU -6566FU
++7574FU
+T24
+'** 268 -7374GI +5784KA -0075FU +7667GI -6566FU +6766GI -7576FU +8776KI
+-7374GI
+T1
+'** 226 +5784KA -0075KE +8493UM -7587NK +7787KI -0075FU +7667GI -0083KI
++5784KA
+T23
+'** 168 -6566FU +0012FU -1112KY +8493UM -0075FU +7685GI -7485GI +8685FU
+-0075FU
+T1
+'** 295 +7667GI -6566FU +6766GI -0065FU +6657GI -7576FU +8776KI -0075FU
++7667GI
+T24
+'** 208 -6566FU +6766GI -0065FU +6657GI -7576FU +7776KI -0075KE +8777KI
+-0081KE
+T1
+'** 146 +0012FU -1112KY +8451UM -7271HI +5152UM -7576FU +6776GI -3242KI
++8451UM
+T16
+'** 107 -7271HI +5184UM -0083FU +0072FU -7172HI +0073FU -8384FU +7372TO
+-9596FU
+T19
+'** 428 +9796FU -7271HI +5152UM -3242KI +5253UM -4353KI %PASS
++5161UM
+T24
+'** 422 -9697TO +9997KY -9397NY +8797KI -7292HI +0084KE -9293HI +0094FU
+-9697TO
+T23
+'** 661 +9997KY -9397NY +8797KI -7576FU +7776KI -7292HI +1714KY -1114KY
++9997KY
+T1
+'** 168 -9397NY +8797KI -7292HI +0084KE -9293HI +0094KY -9363HI
+-9397NY
+T15
+'** 570 +8797KI -7292HI +0094KY -9282HI +1714KY -1114KY +1814HI -0013KY
++8797KI
+T1
+'** 115 -7282HI +2524FU -3324GI +0026KY -2413GI +1828HI -4333KI +0025KE
+-7292HI
+T24
+'** 570 +0084KE -9293HI +0094KY -9363HI +6172UM -0096FU +9796KI -0097FU
++0094KY
+T1
+'** 212 -0093FU +0084KE -9242HI +8472NK -9394FU +7281NK
+-9242HI
+T20
+'** 259 +9491NY -8173KE +9181NY -0066KY +7766KI -6566FU +6766GI -0065FU
++9491NY
+T24
+'** 346 -8173KE +6151UM -5362KA +5142UM -3342GI +0064HI -0063KA +0012FU
+-8173KE
+T1
+'** 251 +6151UM -0076KY +6776GI -7576FU +7776KI -7475GI +7677KI -7566GI
++0026KE
+T23
+'** 181 -0076KY +7787KI -7677KY +8777KI
+-0076KY
+T23
+'** 143 +6776GI -7576FU +7776KI
++7787KI
+T1
+'** -15 -4241HI +6152UM -4191HI +1714KY -9197RY +8897OU -0094KY +0096FU
+-6566FU
+T23
+'** 96 +6766GI -7465GI +6657GI -4241HI +6172UM -0066FU +7263UM -4191HI
++6766GI
+T1
+'** -268 -7465GI +6665GI -7365KE +2614KE -1114KY +1714KY -0013FU +0077FU
+-7465GI
+T24
+'** 3 +6657GI -4241HI +6172UM -0066FU +7273UM -6667TO +7383UM -4191HI
++6657GI
+T1
+'** -194 -0066FU +5768GI -6556GI +0077FU -6667TO +1714KY -1114KY +2614KE
+-0066FU
+T24
+'** -236 +1714KY -0013FU +0074FU -4241HI +6152UM -4191HI +8776KI -0087FU
++0074FU
+T1
+'** -415 -6667TO +7473TO -4241HI +6183UM -6757TO +8365UM -0079GI +8898OU
+-6667TO
+T14
+'** -565 +7473TO -4241HI +6183UM -6777TO +8777KI -7677NY +8877OU -6576GI
++7473TO
+T23
+'** -631 -4241HI +6183UM -7677NY +8777KI -6777TO +8877OU -6576GI +7788OU
+-4241HI
+T1
+'** -553 +6183UM -4191HI +0092FU -7677NY +8777KI -6777TO +8877OU -6576GI
++6183UM
+T24
+'** -766 -7677NY +8777KI -6777TO +8877OU -6576GI +7788OU -0077KI +8899OU
+-7677NY
+T1
+'** -746 +8777KI -6777TO +8877OU -6576GI +7788OU -0077KI +8899OU -0096FU
++8777KI
+T18
+'** -931 -6777TO +8877OU -6576GI +7788OU -0077KI +8899OU -0096FU +9798KI
+-6777TO
+T1
+'** -818 +8877OU -6576GI +7788OU -0077KI +8899OU
++8877OU
+T14
+'** -858 -6576GI +7788OU -0077KI +8879OU -0087FU +0069KE -4191HI +0092FU
+-6576GI
+T23
+'** -806 +7788OU -0077KI +8899OU
++7788OU
+T1
+'** -815 -0077KI +8879OU -0087FU +0089KE -8788TO +1888HI -4191HI +0092FU
+-0077KI
+T24
+'** -828 +8899OU -4191HI +0092FU -0095KY +0098KY -9597NY +9897KY -0088KI
++8879OU
+T1
+'** -1091 -0087FU +0089KE -8788TO +1888HI -4191HI +0092FU -0087FU +8898HI
+-0087FU
+T24
+'** -912 +0069KE -4191HI +0093KY -9181HI +8372UM
++0089KE
+T23
+'** -1125 -8788TO +1888HI -7788KI +7988OU -0087FU +9787KI -7687NG +8887OU
+-8788TO
+T20
+'** -1218 +1888HI -7788KI +7988OU -0087FU +9787KI -7687NG +8887OU -0067HI
++7969OU
+T23
+'** -1357 -8889TO +6958OU -4191HI +0092FU -9181HI +7382TO -8151HI +5848OU
+-8889TO
+T1
+'** -1218 +6959OU -4191HI +0092FU -9171HI +7363TO -5331KA +1714KY -1114KY
++6958OU
+T13
+'** -1425 -0065KE +5748GI -4191HI +0092FU -9181HI +8372UM -8151HI +5849OU
+-4191HI
+T20
+'** -1300 +0092FU -9181HI +8372UM -8171HI +2614KE -1114KY +1714KY -0013FU
++0092FU
+T13
+'** -1186 -9181HI +8372UM -8171HI +7271UM -7667NG +5848OU -5371KA +0041HI
+-9181HI
+T7
+'** -1121 +8372UM -7667NG +5848OU -6757NG +4857OU -0027GI +1858HI -0065KE
++8372UM
+T23
+'** -1099 -8171HI +7271UM -7667NG +5848OU -5371KA +0041HI -0079KA +4171RY
+-8171HI
+T1
+'** -1043 +7271UM -7667NG +5848OU -5371KA +0051HI -0079KA +5171RY -6757NG
++7271UM
+T12
+'** -953 -7667NG +5848OU -5371KA +0051HI -7193KA +2614KE -1114KY +1714KY
+-5371KA
+T23
+'** -856 +0061HI -7667NG +5847OU -0079KA +0068FU -7997UM +6867FU -0027KI
++0051HI
+T24
+'** -953 -7667NG +5848OU -0079KA +0068FU -0065KE +6867FU -7957UM +4838OU
+-0065KE
+T18
+'** -877 +5171RY -0027KA +0052KA -2718UM +1714KY -6557NK
++5766GI
+T13
+'** -1102 -7767KI +5848OU -6766KI +2614KE -2213OU +5121RY
+-7767KI
+T24
+'** -868 +5848OU -6766KI +1714KY -0047KY +4839OU -0027KA +3928OU -2718UM
++5848OU
+T1
+'** -1214 -6766KI +2614KE -1114KY +1714KY -0013FU +1413NY -2113KE +0014FU
+-6766KI
+T15
+'** -928 +1714KY -0013FU +5171RY -1314FU +4838OU -6656KI %PASS
++2614KE
+T23
+'** -1456 -1114KY +1714KY -0013FU +1413NY -2113KE +5171RY -6557NK +4839OU
+-1114KY
+T24
+'** -1075 +1714KY -0013FU +1413KY -2113KE +0014FU -0011KY +5171RY -6557NK
++1714KY
+T1
+'** -1704 -0013FU
+-6557NK
+T23
+'** -1018 +4839OU -0013FU +1413NY -2113KE +0014KY -3324GI +5171RY
++4838OU
+T23
+'** -1225 -0047GI +3828OU -0013FU +1413NY -2113KE +5171RY -6656KI +0011KA
+-0047GI
+T12
+'** -197 +3828OU -0027KY +2827OU -0013FU +1413NY -2113KE +1813RY -2213OU
++3827OU
+T23
+'** -459 -0013FU
+-0016FU
+T1
+'** -185 +1816HI -0038KA +2726OU -0011KY +1411NY -3816UM +2616OU -2211OU
++1816HI
+T24
+'** -375 -3324GI +5171RY -0038KA +2718OU -3233KI +2524FU -3816UM +0031KA
+-0038KA
+T24
+'** -179 +2726OU -3231KI +5171RY -6656KI +0013FU -0011FU +1312TO -1112FU
++2726OU
+T24
+'** -379 -3231KI +5171RY -6656KI +1412NY -2232OU +0052KA -4342KI +5263UM
+-3324GI
+T1
+'** -343 +2524FU -2324FU +0023FU -3223KI +1412NY -2233OU +5131RY -0032KY
++2524FU
+T15
+'** -240 -3816UM +2616OU -2233OU
+-2324FU
+T7
+'** 118 +5171RY -0025KY +2615OU -3816UM +1516OU -0013FU +0026FU -1314FU
++0023FU
+T14
+'** -59 -3223KI +1412NY -2233OU +5131RY -0032KY +3121RY
+-3223KI
+T23
+'** -25 +1412NY -2233OU +5131RY -0032KE +2617OU -0025KY +0028FU -7667NG
++1412NY
+T2
+'** -865 -2233OU +5131RY -0032KE +0022GI -2322KI +3122RY
+-2233OU
+T23
+'** -218 +5131RY -0032KE +2617OU -3816UM +1716OU -0018HI +0017GI -0015FU
++5131RY
+T1
+'** -1029 -0032KE +0027FU -2425FU +2617OU -0015FU +1615HI -0014KY +1514HI
+-0032KE
+T23
+'** -293 +0022GI -2322KI +3122RY -3342OU +0052KI -4252OU +2232RY -5253OU
++0022GI
+T1
+'** -1702 -2322KI +3122RY -3342OU +1615HI -0025KY +1525HI
+-2322KI
+T1
+'** -364 +3122RY -3342OU +0052KI -4252OU +2232RY -5253OU +0017KE
++3122RY
+T19
+'** -2293 -3342OU +0027FU -0025GI +2617OU -4445FU +0053KY -7153KA +0035KY
+-3342OU
+T1
+'** -476 +2917KE -0025KY +1725KE -2425FU
++0025FU
+T23
+'** -1320 -2425FU +2625OU -0024GI +2514OU -3816UM +1221NY
+-2425FU
+T23
+'** -1640 +2625OU -0024GI +2224RY -3816UM +2516OU -3224KE
++2625OU
+T1
+'** -1682 -0024GI +2514OU -3816UM +0052KI -4252OU +2232RY -0042KY +0064KE
+-0024GI
+T13
+'** -1671 +2224RY -3816UM +2516OU -3224KE
++2514OU
+T23
+'** -2271 -3816UM +0052KI -4252OU +2232RY -0042KI +0064KE -5253OU +3221RY
+-3816UM
+T1
+'** -2219 +0026KI -4333KI +2616KI -0013FU +1213NY -2413GI +2213RY -0024HI
++0052KI
+T14
+'** -2479 -4252OU +2232RY -0042KI +0064KE -5253OU +3221RY -5364OU +2171RY
+-4252OU
+T1
+'** 15081406 +2232RY
++2232RY
+T23
+'** -2479 -0042KI +0064KE -5253OU +1423OU -4738NG +9291TO %PASS
+-0042KY
+T1
+'** -3512 +0064KE -5253OU +1423OU -0033KI +2322OU -3332KI
++0064KE
+T19
+'** -3676 -5253OU +1423OU -0033KI +2322OU -3332KI +2232OU -5364OU +0072FU
+-5253OU
+T4
+'** -1992 +3221RY -4333KI +2151RY -5364OU +5161RY -6473OU +6171RY -7363OU
++1423OU
+T23
+'** -3659 -0033KI +3233RY -4333KI +2322OU -5364OU
+-0033KI
+T24
+'** -3893 +3233RY -4333KI +2322OU -5364OU +0019KY -1649UM +0072KI -0023HI
++3233RY
+T1
+'** -3790 -4333KI +2322OU -5364OU +0072FU -0032HI +2211OU -7193KA +0063KI
+-4333KI
+T24
+'** -3742 +2322OU -5364OU +0072FU -7193KA +7383TO -0067HI +8393TO -6797RY
++2322OU
+T1
+'** -3921 -5364OU +0072FU -0051HI +7271TO -5171HI +0063KI
+-5364OU
+T17
+'** -937 +0072FU -7193KA +7383TO -0067HI +9796KI -6787RY
++0072FU
+T6
+'** -3458 -7153KA +0063KI -6465OU +6353KI -6556OU +5342KI %PASS
+-7193KA
+T23
+'** -1031 +7383TO -3435FU +0025FU -0032HI +2211OU -1625UM
++7383TO
+T1
+'** -3302 -0032HI +2211OU -3435FU +0025FU -3536FU +8393TO
+-3435FU
+T24
+'** -3217 +3635FU -0036FU +3728GI -0027FU +2817GI -1643UM
++3635FU
+T24
+'** -3483 -1643UM +2211OU -3332KI +8393TO -4333UM +0022KA
+-0036FU
+T14
+'** -3320 +8393TO -3637TO +7271TO
++8393TO
+T24
+'** -3339 -1643UM +2211OU -3637TO +0014FU -0032GI +2937KE
+-3637TO
+T1
+'** -3518 +0025FU -0032HI +2211OU -2435GI
++2211OU
+T23
+'** -3596 -6465OU +0022FU -6556OU +2221TO
+-0023GI
+T13
+'** -3458 +1222NY -6465OU
++0022KI
+T6
+'** -3443 -1643UM +2937KE -0036FU +1221NY
+-2312GI
+T24
+'** -3282 +2212KI -5756NK +0082KA -6453OU
++2212KI
+T1
+'** -3447 -4756NG
+-0099HI
+T23
+'** -3117 +0022FU -9997RY +2221TO -6465OU
++0098KY
+T22
+'** -3256 -0096FU +0022FU -9697TO +2221TO
+-0096FU
+T24
+'** -3478 %PASS
++0022FU
+T12
+'** -3903 -9697TO +2221TO -9998RY +2937KE
+-1643UM
+T6
+'** -3759 +9796KI -9998RY %PASS
++0067FU
+T16
+'** -3626 -7667NG +2221TO -9697TO +9897KY
+-5767NK
+T14
+'** -3978 +9796KI -9998RY %PASS
++0068FU
+T23
+'** -3912 -6768NK +2221TO -9697TO +9897KY -9997RY +2937KE
+-6768NK
+T19
+'** -4254 +9796KI -9998RY +1221KI -9896RY
++2221TO
+T24
+'** -4400 -9697TO +0034KY -9998RY +3433NY -4333UM +0022GI
+-9697TO
+T18
+'** -4212 +9291TO
++0034KY
+T5
+'** -4434 -6465OU +3433NY -2433GI +0083KA -0074KY +2937KE
+-9998RY
+T22
+'** -4401 +2937KE
++3433NY
+T1
+'** -4456 -4333UM +0022GI -3332UM +0034KI
+-2433GI
+T24
+'** -4584 +0084KI %PASS
++0084KI
+T15
+'** -4282 %PASS
+-0063KI
+T19
+'** -4064 +9291TO -6656KI +2937KE -6455OU
++2937KE
+T23
+'** -3978 -4756NG +0034GI -3334GI +3534FU -4334UM +0026KE
+-6465OU
+T1
+'** -4145 +0041KA -6556OU %PASS
++0025KA
+T13
+'** -4594 -6556OU +2543UM -4243KY +0041KA -5646OU +4163UM
+-6556OU
+T24
+'** -4596 +2543UM -4243KY +0041KA -6353KI +4123UM -5646OU +2333UM -4637OU
++2543UM
+T1
+'** -4590 -4243KY +0041KA -6353KI +4132UM -5646OU +3233UM
+-4243KY
+T19
+'** -4651 +0032KA -6353KI +3223UM -5646OU +2333UM -4637OU
++0041KA
+T1
+'** -4656 -6353KI +4123UM -5646OU +2333UM
+-0062HI
+T13
+'** -4453 +4123UM -5646OU +2333UM -0078KA
++0051GI
+T13
+'** -3906 -6261HI +4152UM -6151HI +5251UM
+-6261HI
+T23
+'** -4187 +4123UM -5646OU +2333UM -4637OU +7271TO -6171HI +9382TO -7161HI
++4123UM
+T1
+'** -4301 -5646OU +2333UM -4637OU +0052GI -6181HI +5263NG
+-5646OU
+T24
+'** -3770 +2333UM -4637OU +7271TO -6171HI +9382TO -7151HI +3351UM -3748OU
++2333UM
+T1
+'** -4378 -4637OU +0052GI %PASS
+-4637OU
+T24
+'** -3706 +7271TO -6171HI +9382TO -7151HI +3351UM -3748OU
++0052GI
+T1
+'** -3828 -0041KE +3315UM -3736OU +5261NG
+-6181HI
+T24
+'** -3859 +5263NG -8184HI +3343UM -0038FU +7271TO -3839TO
++5263GI
+T1
+'** -3862 -3738OU +9291TO -8184HI +3343UM
+-8184HI
+T12
+'** -3879 +3343UM -8486HI +9291TO
++3343UM
+T11
+'** -4073 -3748OU +7271TO -0023KI +2122TO
+-8486HI
+T23
+'** -3865 +3534FU -8687RY +9291TO -3748OU
++6354NG
+T1
+'** -3808 -7667NG +9291TO -8688RY +7271TO
+-0053FU
+T13
+'** -3811 +4344UM -7667NG
++5453NG
+T10
+'** -3675 -8688RY +7271TO -8884RY +0029KY
+-0057FU
+T12
+'** -3682 +9291TO -8688RY
++3534FU
+T23
+'** -3637 %PASS
+-5758TO
+T23
+'** -3568 +3433TO -3748OU +4344UM -4756NG
++4344UM
+T1
+'** -3533 -4756NG +3433TO -8688RY +4435UM
+-4756NG
+T23
+'** -3687 +7271TO -3748OU +4426UM -4857OU