#!/usr/bin/perl -I.
# Dreamcast Version
# SONIC ADVENTURE
# World Rankings Displayer
# 


use strict;

use CGI;
use	DC;
use POSIX	'strftime';
use DB;


## Set up variables
use vars	(	'$dc',	# DC object
				'@IN', '@BINDATA', '$PDATA', '$WRANK', '@oldDATA', '$allrank', '$todayrank',
				'$errorURL', '$cgiPath', '$date',
				'$Type', '$mode', '$EventID', '$value', '$ftype', '$Assort', '$Stage', '$Chara', '$present', '$contest',
				'%GameType', '%CharaName', '@SakanaName', '%StageName', '%TimeTbl', '%ScoreTbl', '%BWeightTbl', '%CircuitTbl',
				'$MAX_ENTRY', '$MODE', '$MAX', '$START', '$END', '$UserKey', '$MaxRec', '$nextflag',
			);

$MAX_ENTRY=300000;	# Maximum Number of Recorded Entries
$MAX = 10;			# Default number of menu choices

%GameType = ( 'TIME','Time','SCORE','Score',
              'WEIGHT','Weight','OTHER','Other',
			  'CIRCUIT', 'Circuit');

%CharaName = ( 'SONIC','Sonic','TAILS','Tails',
              'KNUCK','Knuckles','AMY','Amy',
              'BIG','Big','E102','E-102 Gamma','OTHER','Other' );

@SakanaName = ( 'Frog','Sea Bass','Black Bass','Coelacanth','Red Cod',
                'Rock Cod','Swordfish','Salmon','Angler','Piranha',
                'Shark','Hammerhead Shark','Mechanical Fish','Eel',
                'Moray','Ribbon Fish'
              );

%StageName = ( 'EME','Emerald Coast',
               'WIN','Windy Valley',
               'TWI','Twinkle Park',
               'SPE','Speed Highway',
               'RED','Red Mountain',
               'SKY','Sky Deck',
               'LOS','Lost World',
               'ICE','Ice Cap',
               'CAJ','Casinopolis',
               'HOT','Hot Shelter',
               'FIN','Final Egg',
               'CH1','Sky Chase 1',
               'CH2','Sky Chase 2',
               'MIC','Ice Cap',
               'CIR','Twinkle Circuit',
               'SAN','Sandhill',
               'HED','Hedgehog Hammer',
			   'BOS','Boss',
               'OT1','Special 1',
               'OT2','Special 2',
               'OT3','Special 3',
               'OT4','Special 4',
               'OT5','Special 5',
               'OT6','Special 6',
               'OT7','Special 7',
               'OT8','Special 8',
             );

# Time Attack Related Data
%TimeTbl = (
		# key => [ Character, Screen Shot, Music, Pointer ]
		'EME:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_ec_2.gif", "file:/sonicadv/ecoast1.adx",   0 ],
		'WIN:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_wv_1.gif", "file:/sonicadv/wndyvly1.adx",  1 ],
		'TWI:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_tp_2.gif", "file:/sonicadv/TWNKLPK1.ADX",  2 ],
		'SPE:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_sh_2.gif", "file:/sonicadv/HIGHWAY1.ADX",  3 ],
		'RED:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_rm_4.gif", "file:/sonicadv/REDMNTN1.ADX",  4 ],
		'SKY:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_sd_7.gif", "file:/sonicadv/skydeck1.adx",  5 ],
		'LOS:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_lw_3.gif", "file:/sonicadv/LSTWRLD2.ADX",  6 ],
		'ICE:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_ic_6.gif", "file:/sonicadv/icecap1.adx",   7 ],
		'CAJ:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_cas_1.gif","file:/sonicadv/casino1.adx",   8 ],
		'FIN:SONIC'=>[ "file:/character_sonic.gif",		"file:/sshot_s_fe_3.gif", "file:/sonicadv/FINALEG1.ADX",  9 ],
		'WIN:TAILS'=>[ "file:/character_tails.gif",		"file:/sshot_t_wv_3.gif", "file:/sonicadv/WNDYVLY3.ADX", 10 ],
		'SPE:TAILS'=>[ "file:/character_tails.gif",		"file:/sshot_t_sh_4.gif", "file:/sonicadv/HIGHWAY1.ADX", 11 ],
		'SKY:TAILS'=>[ "file:/character_tails.gif",		"file:/sshot_t_sd_3.gif", "file:/sonicadv/SKYDECK2.ADX", 12 ],
		'ICE:TAILS'=>[ "file:/character_tails.gif",		"file:/sshot_t_ic_1.gif", "file:/sonicadv/ICECAP3.ADX",  13 ],
		'CAJ:TAILS'=>[ "file:/character_tails.gif",		"file:/sshot_t_cas_1.gif","file:/sonicadv/casino2.adx",  14 ],
		'SPE:KNUCK'=>[ "file:/character_knuckles.gif",	"file:/sshot_k_sh_5.gif", "file:/sonicadv/HIGHWAY2.ADX", 15 ],
		'RED:KNUCK'=>[ "file:/character_knuckles.gif",	"file:/sshot_k_rm_3.gif", "file:/sonicadv/REDMNTN1.ADX", 16 ],
		'SKY:KNUCK'=>[ "file:/character_knuckles.gif",	"file:/sshot_k_sd_2.gif", "file:/sonicadv/SKYDECK2.ADX", 17 ],
		'LOS:KNUCK'=>[ "file:/character_knuckles.gif",	"file:/sshot_k_lw_3.gif", "file:/sonicadv/LSTWRLD3.ADX", 18 ],
		'CAJ:KNUCK'=>[ "file:/character_knuckles.gif",	"file:/sshot_k_cas_6.gif","file:/sonicadv/casino4.adx",  19 ],
		'TWI:AMY'  =>[ "file:/character_amy.gif",		"file:/sshot_a_tp_2.gif", "file:/sonicadv/TWNKLPK1.ADX", 20 ],
		'FIN:AMY'  =>[ "file:/character_amy.gif",		"file:/sshot_a_fe_5.gif", "file:/sonicadv/FINALEG2.ADX", 21 ],
		'HOT:AMY'  =>[ "file:/character_amy.gif",		"file:/sshot_a_hs_4.gif", "file:/sonicadv/shelter1.adx", 22 ],
		'EME:E102' =>[ "file:/character_e102.gif",		"file:/sshot_e_ec_6.gif", "file:/sonicadv/ECOAST1.ADX",  23 ],
		'WIN:E102' =>[ "file:/character_e102.gif",		"file:/sshot_e_wv_1.gif", "file:/sonicadv/wndyvly1.adx", 24 ],
		'RED:E102' =>[ "file:/character_e102.gif",		"file:/sshot_e_rm_3.gif", "file:/sonicadv/REDMNTN2.ADX", 25 ],
		'FIN:E102' =>[ "file:/character_e102.gif",		"file:/sshot_e_fe_1.gif", "file:/sonicadv/FINALEG2.ADX", 26 ],
		'HOT:E102' =>[ "file:/character_e102.gif",		"file:/sshot_e_hs_5.gif", "file:/sonicadv/shelter2.adx", 27 ],
		'EME:BIG'  =>[ "file:/character_big.gif",		"file:/sshot_b_ec_2.gif", "file:/sonicadv/ECOAST2.ADX",  28 ],
		'TWI:BIG'  =>[ "file:/character_big.gif",		"file:/sshot_b_tp_2.gif", "file:/sonicadv/twnklpk2.adx", 29 ],
		'ICE:BIG'  =>[ "file:/character_big.gif",		"file:/sshot_b_ic_1.gif", "file:/sonicadv/ICECAP2.ADX",  30 ],
		'HOT:BIG'  =>[ "file:/character_big.gif",		"file:/sshot_b_hs_4.gif", "file:/sonicadv/shelter1.adx", 31 ],
        );

# Score Attack Related Data
%ScoreTbl = (
        # key => [ Character, Screen Shot, Music, Pointer , 1st Place for first part ,2nd Place for first part , 3rd Place for first part ]
        'CH1:SONIC'=>[ "file:/character_sonic.gif", "file:/sshot_s_mg_plane_1.gif", "file:/sonicadv/SCRAMBLE.ADX", 324 ,  8000 ,  6000,  3000 ],
        'CH1:TAILS'=>[ "file:/character_tails.gif", "file:/sshot_s_mg_plane_2.gif", "file:/sonicadv/SCRAMBLE.ADX", 336 ,  8000 ,  6000,  3000 ],
        'CH2:SONIC'=>[ "file:/character_sonic.gif", "file:/sshot_s_mg_plane_3.gif", "file:/sonicadv/SCRAMBLE.ADX", 348 , 20000 , 15000, 10000 ],
        'CH2:TAILS'=>[ "file:/character_tails.gif", "file:/sshot_s_mg_plane_3.gif", "file:/sonicadv/SCRAMBLE.ADX", 360 , 20000 , 15000, 10000 ],
        'MIC:SONIC'=>[ "file:/character_sonic.gif", "file:/sshot_s_ic_6.gif",		"file:/sonicadv/ICECAP2.ADX",  372 ,  9000 ,  6000,  3000 ],
        'MIC:TAILS'=>[ "file:/character_tails.gif", "file:/sshot_t_ic_1.gif",		"file:/sonicadv/ICECAP3.ADX",  384 ,  9000 ,  6000,  3000 ],
        'SAN:SONIC'=>[ "file:/character_sonic.gif", "file:/sshot_t_mg_sand_1.gif",	"file:/sonicadv/SANDHILL.ADX", 396 , 10000 ,  6000,  3000 ],
        'SAN:TAILS'=>[ "file:/character_tails.gif", "file:/sshot_t_mg_sand_1.gif",	"file:/sonicadv/SANDHILL.ADX", 408 , 10000 ,  6000,  3000 ],
        'HED:AMY'  =>[ "file:/character_amy.gif",	"file:/sshot_a_mg_ham_1.gif",	"file:/sonicadv/HAMMER.ADX",   420 ,  2000 ,  1500,  1000 ]
        );

# Biggest Weight Related Data
%BWeightTbl = (
        # key => [ Character, Screen Shot, Music, Pointer ]
        'EME:BIG'=>[ "file:/character_big.gif", "file:/sshot_b_ec_2.gif", "file:/sonicadv/ECOAST2.ADX",  244 ],
        'TWI:BIG'=>[ "file:/character_big.gif", "file:/sshot_b_tp_2.gif", "file:/sonicadv/twnklpk2.adx", 248 ],
        'ICE:BIG'=>[ "file:/character_big.gif", "file:/sshot_b_ic_1.gif", "file:/sonicadv/ICECAP2.ADX",  252 ],
        'HOT:BIG'=>[ "file:/character_big.gif", "file:/sshot_b_hs_4.gif", "file:/sonicadv/shelter1.adx", 256 ]
        );

# Circuit Attack Related Data
%CircuitTbl = (
        # key => [ Character, Screen Shot, Music, Pointer , 1st Place for first part ,2nd Place for first part , 3rd Place for first part ]
# shilpa changed next line.
        'CIR:SONIC'=>[ "file:/character_sonic.gif",		"/images/wrank/screen_s_tc.gif", "file:/sonicadv/circuit.adx", 432, 100000, 150000, 200000 ],
        #'CIR:SONIC'=>[ "file:/character_sonic.gif",		"/images/wrank/screen_s_tc.gif", "file:/sonicadv/circuit.adx", 432, 36000, 54000, 72000 ],
        'CIR:TAILS'=>[ "file:/character_tails.gif",		"/images/wrank/screen_t_tc.gif", "file:/sonicadv/circuit.adx", 447, 36000, 54000, 72000 ],
        'CIR:KNUCK'=>[ "file:/character_knuckles.gif",	"/images/wrank/screen_k_tc.gif", "file:/sonicadv/circuit.adx", 462, 36000, 54000, 72000 ],
        'CIR:AMY'  =>[ "file:/character_amy.gif",		"/images/wrank/screen_a_tc.gif", "file:/sonicadv/circuit.adx", 477, 36000, 54000, 72000 ],
        'CIR:E102' =>[ "file:/character_e102.gif",		"/images/wrank/screen_e_tc.gif", "file:/sonicadv/circuit.adx", 492, 36000, 54000, 72000 ],
        'CIR:BIG'  =>[ "file:/character_big.gif",		"/images/wrank/screen_b_tc.gif", "file:/sonicadv/circuit.adx", 507, 36000, 54000, 72000 ],
        );


#...............................................
# Handling time
	$date = strftime("UPLOADED ON %m/%d/%Y, %I:%M %p (%Z)", localtime);

	my $q = new CGI;
	$dc = new DC($q);
	$dc->q->import_names('IN');

	$errorURL = "world_rankings.html";
	$cgiPath = "/cgi-bin/soa/sonicadv/score.cgi";

	@BINDATA = ();
	$PDATA = "";
	$WRANK = "";
	$nextflag = 1;
	$Type = 0;

	if($dc->q->param('command') eq "")
	{
		&check_data(1);		# First time through
	} else {
		&check_data(0);
	}
    
    if (($Type >= 0) && ($Type <= 4)) {
		if ($dc->q->param('command') eq 'menu')
		{
			my $cookie = $dc->q->cookie(-name => 'world_ranking',
#									-value   => 'Kiss my ass',
									-value   => [$dc->q->param('ASSORT'),
												 $dc->q->param('STAGE'),
												 $dc->q->param('CHARA')],
									-expires => '+1d',
									-path    => '/cgi-bin/soa/sonicadv');

			#print $dc->q->header(-cookie => $cookie). "\n";
			print "Set-Cookie: ".$cookie."\n";
			
			print "Cache-control: no-cache\n";
			
			# Menu template
			if ($contest == 0)
			{
				$dc->output_form("html/rank_menu.html");
			}
			elsif ($contest == 1)
			{
				$dc->output_form("html/rank_menu_pending.html");
			}
			elsif ($contest == 2)
			{
				$dc->output_form("html/rank_menu_winners.html");
			}
			else
			{
				$dc->output_form("html/rank_menu_closed.html");
			}
		} elsif($dc->q->param('command') eq 'form') {
			# Form output again
			$dc->output_form("html/rank_form.html");
		} elsif($dc->q->param('command') eq "") {
			# Form output again
			$dc->output_form("html/rank_form.html");
		} elsif ($dc->q->param('command') eq 'search') {
			&check_search;
			# Form output again
			$dc->output_form("html/rank_search.html");
		} elsif ($dc->q->param('command') eq 'view') {
			&check_search;
			&output_records(&read_data());
		} elsif ($dc->q->param('command') eq 'verify') {
			# Record data into Database
			my ($dbh, $errN, $errstr, @row, $key);
			
			
			# Read user information from the table
			$key = $dc->make_key($IN::mailid);

			($dbh, $errstr) = DB::openOracleConnection();
			if( !$dbh )
			{
				$dc->error("[score] Error connecting to database: $errstr");
			}

			# Update user table information
			($errN, $errstr, @row) = DB::getRow_UserByUK( $dbh, $dc->DBaseTable('USER'), $key );
			if ($errN)
			{
				$dc->error("[score] Fetching user key: $errN .... $errstr", $errorURL);
			}

			my $emblems = &Count_Emblems();

			# Ensure that emblem count never decreases
			if ($row[$dc->UserOff('EMBLEMS')] > $emblems)
			{
				$emblems = $row[$dc->UserOff('EMBLEMS')];
			}

			($errN, $errstr)       = DB::modifyRow_UserByEmail( $dbh, $dc->DBaseTable('USER'), $IN::mailid, $dc->q->param('NAME'), $dc->q->param('CITY'), $IN::STATE, $IN::COUNTRY, $IN::MAIL, $WRANK, $row[$dc->UserOff('BIRTH')], $row[$dc->UserOff('PARENT')], $row[$dc->UserOff('BLOCK')], $row[$dc->UserOff('P1EMAIL')], $row[$dc->UserOff('P2EMAIL')], time, $row[$dc->UserOff('PENDING')], $emblems, $row[$dc->UserOff('GOLD')], $row[$dc->UserOff('SILVER')], $row[$dc->UserOff('BRONZE')], $row[$dc->UserOff('BLUERIB')] );
			if ($errN)
			{
				$dc->error("[score] Unable to update user info: $errN .... $errstr", $errorURL);
			}

			DB::closeOracleConnection( $dbh );

			# Enter the data into the World Ranking Database
			my $added = new_record($key);

			$allrank = determine_rank($key, $EventID, "ALL");
			$todayrank = determine_rank($key, $EventID, "TODAY");

			# Display Record
			&output_verify($added);
		}
	}

exit(0);

#--------------------------------------------------------
# Data Check
#--------------------------------------------------------
sub check_data
{
	my $first = shift;

	my $MAIL = "";
    my $Warning = "";
	my ($dbh, $errN, $errstr, @row, $key, $val);

	if($dc->q->param('command') eq "")
	{
#-------------------------------------------------
# BIG HACK - Remove once Black Market is working
#-------------------------------------------------
#begin 
		my $where = $dc->q->cookie('chao');
		# if (($dc->get_browser() == 2) && ($dc->q->param('ASSORT') eq 'OTHER') &&
			# ($dc->q->param('CHARA') eq 'OTHER') && ($dc->q->param('STAGE') eq 'OT2'))
			
		if ($where eq "blackmarket")
		{
			# Don't bother processing if just viewing the World Rankings

			# Data Decode
			if( &decode($dc->q->param('chaodata')) != 0) {
				$dc->error("Something wrong with your ranking data.<BR>Please recreate the Ranking upload file and try again.", $errorURL);
			}

			# Hardware ID decode - Not Used
			# &decode_hwid(substr($dc->q->param('dcid'),0,12));

			my $emblems = &Count_Emblems();
			$dc->q->param('Emblems', $emblems);
			$dc->q->param('EMBLEM', $emblems);
			if($emblems < 100) {
				# outout the page for insufficient number of emblems
				$dc->output_form("html/chao_blkmkt_not_enough.html");
			} else {
				# outout the page for enough number of emblems
				$dc->output_form("html/chao_blkmkt_knights.html");
			}

			exit(0);
		}
#end 1999.10.28 t-saito 
#-------------------------------------------------

		my @level = $dc->q->cookie(-name=>'world_ranking');
		if (($level[0] eq "") || ($level[1] eq "") || ($level[2] eq ""))
		{
			$dc->error("Cookie of \"world_ranking\" has not been set.<BR>Please make sure your Dreamcast clock is correct.", $errorURL);
		}

		$dc->q->param('ASSORT', $level[0]);
		$dc->q->param('STAGE', $level[1]);
		$dc->q->param('CHARA', $level[2]);
	}

    $Assort = $dc->q->param('ASSORT');
    $Stage = $dc->q->param('STAGE');
    if(!defined($StageName{$Stage})) {
        $dc->error("Invalid stage was chosen.<BR>Please select a different stage.", $errorURL);
    }
	$dc->q->param('StageName', $StageName{$Stage});
 
    $Chara = $dc->q->param('CHARA');
    if(!defined($CharaName{$Chara})) {
        $dc->error("Invalid character was chosen.<BP>Please select a different character.", $errorURL);
    }

    if($Assort eq 'TIME') {
		$Type = 0;
        if(defined($TimeTbl{"${Stage}:${Chara}"})) {
            $val = "${Stage}:${Chara}";
			$dc->q->param('CharFile', $TimeTbl{$val}->[0]);
			$dc->q->param('StageFile', $TimeTbl{$val}->[1]);
			$dc->q->param('AdxFile', $TimeTbl{$val}->[2]);
			$EventID = $TimeTbl{$val}->[3];
			$dc->q->param('EventID', $EventID);

			$dc->q->param('CharType', 'Character');
			$dc->q->param('CharaName', $CharaName{$Chara});
			$dc->q->param('GAMETYPE', $Assort);
			$dc->q->param('GameType', $GameType{$Assort});
        } else {
            $dc->error("There are no times in $StageName{$Stage} with $CharaName{$Chara}.", $errorURL);
        }
    } elsif($Assort eq 'SCORE') {
		$Type = 1;
        if(defined($ScoreTbl{"${Stage}:${Chara}"})) {
            $val = "${Stage}:${Chara}";
			$dc->q->param('CharFile', $ScoreTbl{$val}->[0]);
			$dc->q->param('StageFile', $ScoreTbl{$val}->[1]);
			$dc->q->param('AdxFile', $ScoreTbl{$val}->[2]);
			$EventID = $ScoreTbl{$val}->[3];
			$dc->q->param('EventID', $EventID);

			$dc->q->param('CharType', 'Character');
			$dc->q->param('CharaName', $CharaName{$Chara});
			$dc->q->param('GAMETYPE', $Assort);
			$dc->q->param('GameType', $GameType{$Assort});
        } else {
            $dc->error("There are no scores in $StageName{$Stage} with $CharaName{$Chara}.", $errorURL);
        }
    } elsif($Assort eq 'WEIGHT') {
		$Type = 2;
        if(defined($BWeightTbl{"${Stage}:${Chara}"})) {
            $val = "${Stage}:${Chara}";
			$dc->q->param('CharFile', $BWeightTbl{$val}->[0]);
			$dc->q->param('StageFile', $BWeightTbl{$val}->[1]);
			$dc->q->param('AdxFile', $BWeightTbl{$val}->[2]);
			$EventID = $BWeightTbl{$val}->[3];
			$dc->q->param('EventID', $EventID);

			$dc->q->param('CharType', 'Fish');
			$dc->q->param('CharaName', $CharaName{$Chara});
			$dc->q->param('GAMETYPE', $Assort);
			$dc->q->param('GameType', $GameType{$Assort});
        } else {
            $dc->error("There are no fish weights in $StageName{$Stage} with $CharaName{$Chara}.", $errorURL);
        }
    } elsif($Assort eq 'OTHER') {
        if($Chara eq 'OTHER' && $Stage eq 'OT1') {
            $Type = 3;
			$dc->q->param('CharFile',  "/images/wrank/character_emblem_attack.gif");
			$dc->q->param('StageFile', "/images/wrank/sshot_emblem_attack.gif");
			$dc->q->param('AdxFile',   "file:/sonicadv/jingle_5.adx");
			$EventID = 999;
			$dc->q->param('EventID', $EventID);

			$dc->q->param('GAMETYPE', 'EMBLEM');
			$dc->q->param('GameType', 'Emblem');
			$dc->q->param('StageName', 'Sonic Adventure');
			$dc->q->param('CharType', 'Time');
			$dc->q->param('CharaName', 'All emblems earned');
        } else {
            $dc->error("Do you know something we don't know?<br>We haven't told you about \"OTHER\" on $StageName{$Stage} yet?!?", $errorURL);
        }
    } elsif($Assort eq 'CIRCUIT') {
		$Type = 4;
        if(defined($CircuitTbl{"${Stage}:${Chara}"})) {
            $val = "${Stage}:${Chara}";
			$dc->q->param('CharFile', $CircuitTbl{$val}->[0]);
			$dc->q->param('StageFile', $CircuitTbl{$val}->[1]);
			$dc->q->param('AdxFile', $CircuitTbl{$val}->[2]);
			$EventID = $CircuitTbl{$val}->[3];
			$dc->q->param('EventID', $EventID);

			$dc->q->param('CharType', 'Character');
			$dc->q->param('CharaName', $CharaName{$Chara});
			$dc->q->param('GAMETYPE', $Assort);
			$dc->q->param('GameType', $GameType{$Assort});
        } else {
            $dc->error("There are no circuit races in $StageName{$Stage} with $CharaName{$Chara}.", $errorURL);
        }
    } else {
        $dc->error("The contest type information is missing.<BR>Please start over.", $errorURL);
    }

	# Now that the stage has been verified, it now needs to check to see if it live.
	my $adminkey = $dc->get_key($dc->DBaseTable('ADMIN'));

	($dbh, $errstr) = DB::openOracleConnection();
	if( !$dbh )
	{
		$dc->error("[score] Error connecting to database: $errstr");
	}

	# Read the current contest controlling entry in the database
	($errN, $errstr, @row) = DB::getRow_WRankByUKandEVENT( $dbh, $dc->DBaseTable('WRANK'), $adminkey, $EventID );
	if ($errN)
	{
		$dc->error("[score] Fetching WRank Event Info #$EventID: $errN .... $errstr", $errorURL);
	}
	
	if ($row[$dc->WRankOff('KEY')] eq $adminkey)
	{
		$present = $row[$dc->WRankOff('FTYPE')];
		$contest = $row[$dc->WRankOff('VALUE')];
	}
	else
	{
		$present = -1;
		$contest = -1;
	}
	DB::closeOracleConnection( $dbh );

	# Ensure user isn't trying to enter a contest that is closed or pending
	if ($IN::command eq "")
	{
		if (($contest != 0) && ($contest != 2))
		{
			# Menu template
			if ($contest == 1)
			{
				$dc->output_form("html/rank_menu_pending.html");
				exit(0);
			}
			else
			{
				$dc->output_form("html/rank_menu_closed.html");
				exit(0);
			}
		}
	}

	if (($IN::command eq "") || ($IN::command eq "form") || ($IN::command eq "verify"))
	{
		# Don't bother processing if just viewing the World Rankings

		# Data Decode
		if( &decode($dc->q->param('chaodata')) != 0) {
			$dc->error("Something wrong with your ranking data.<BR>Please recreate the Ranking upload file and try again.", $errorURL);
		}

		# Hardware ID decode - Not Used
		# &decode_hwid(substr($dc->q->param('dcid'),0,12));

		# Distinction between Application Types
		if($Assort eq 'TIME') {
			my $ptr;
			$ptr = 68 + 136 + ($EventID)*3;
			$ftype = 0;
			$value = ($BINDATA[$ptr]*3600)+($BINDATA[$ptr+1]*60)+$BINDATA[$ptr+2];
			$dc->q->param('Score',  $dc->calc_int_time($value));
		} elsif($Assort eq 'SCORE') {
            my $key = "${Stage}:${Chara}";
			my $ptr = 68 + $EventID;
			$ftype = 0;
			my $val1 = ($BINDATA[$ptr+3]<<24)+($BINDATA[$ptr+2]<<16)+($BINDATA[$ptr+1]<<8 )+($BINDATA[$ptr]);
			my $val2 = ($BINDATA[$ptr+7]<<24)+($BINDATA[$ptr+6]<<16)+($BINDATA[$ptr+5]<<8 )+($BINDATA[$ptr+4]);
			my $val3 = ($BINDATA[$ptr+11]<<24)+($BINDATA[$ptr+10]<<16)+($BINDATA[$ptr+9]<<8 )+($BINDATA[$ptr+8]);
			if($val1 > $ScoreTbl{$key}->[4]) {
				$value = $val1;
			} elsif($val2 > $ScoreTbl{$key}->[5]) {
				$value = $val2;
			} elsif($val3 > $ScoreTbl{$key}->[6]) {
				$value = $val3;
			} else {
				$dc->error("You need over $ScoreTbl{$key}->[6] points to enter.<BR>The following scores will not be recorded.<BR>1st=$val1, 2nd=$val2, 3rd=$val3", $errorURL);
			}
			$dc->q->param('Score', sprintf " %d",
				$value);
		} elsif($Assort eq 'WEIGHT') {
			my $ptr = 68 + $EventID;
			$value = ($BINDATA[$ptr+1]<<8 )+($BINDATA[$ptr]);
			$ftype = ($BINDATA[$ptr+3]<<8 )+($BINDATA[$ptr+2]);
			$dc->q->param('Score', sprintf " %d grams",
				$value);
			$dc->q->param('CharaName', $SakanaName[$ftype]);
		} elsif($Assort eq 'OTHER') {
	        if(${Chara} eq 'OTHER' && $Stage eq 'OT1') {
				my $ptr = 68 + 4;
				$ftype = &Count_Emblems();
				$value = ($BINDATA[$ptr+3]<<24)+($BINDATA[$ptr+2]<<16)+($BINDATA[$ptr+1]<<8 )+($BINDATA[$ptr]);
				$dc->q->param('Score', $ftype);
				$dc->q->param('CharaName', sprintf " %d : %02d . %02d",
					int($value/216000),
					int(($value%216000)/3600),
					int(($value%60)*1.66));
			}
		} elsif($Assort eq 'CIRCUIT') {
            my $key = "${Stage}:${Chara}";
			my $ptr = 68 + $EventID;
			$ftype = 0;
#shilpa changed next line.
			my $val1 = ($BINDATA[$ptr]*10000)+($BINDATA[$ptr+1]*100)+$BINDATA[$ptr+2];
			my $val2 = ($BINDATA[$ptr+3]*10000)+($BINDATA[$ptr+4]*100)+$BINDATA[$ptr+5];
			my $val3 = ($BINDATA[$ptr+6]*10000)+($BINDATA[$ptr+7]*100)+$BINDATA[$ptr+8];
			#my $val1 = ($BINDATA[$ptr]*3600)+($BINDATA[$ptr+1]*60)+$BINDATA[$ptr+2];
			#my $val2 = ($BINDATA[$ptr+3]*3600)+($BINDATA[$ptr+4]*60)+$BINDATA[$ptr+5];
			#my $val3 = ($BINDATA[$ptr+6]*3600)+($BINDATA[$ptr+7]*60)+$BINDATA[$ptr+8];
			if($val1 < $CircuitTbl{$key}->[4]) {
				$value = $val1;
				$dc->q->param('Score', sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2)));
			} elsif($val2 < $CircuitTbl{$key}->[5]) {
				$value = $val2;
				$dc->q->param('Score', sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2)));
			} elsif($val3 < $CircuitTbl{$key}->[6]) {
				$value = $val3;
				$dc->q->param('Score', sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2)));
			} else {
				my ($out1, $out2, $out3, $out4);
				$out1 = sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2));
				$out2 = sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2));
				$out3 = sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2));
				$out4 = sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2));

				$dc->error("You must be faster than $out1 to enter.<BR>The following times will not be recorded.<BR>1st=$out2, 2nd=$out3, 3rd=$out4", $errorURL);
			}
		}

		# Key Acquisition
		$MAIL = $dc->q->param('mailid');
		$MAIL =~ y/A-Z/a-z/;
		$dc->q->param('mailid', $MAIL);
		if($MAIL eq "" || $MAIL =~ /[^a-z0-9_\-\.\@]/) {
			$dc->error("Something wrong with E-mail address \"$MAIL\".<BR>Please make sure there are no spaces at the end of your E-mail address.", $errorURL);
		}

		if ($first == 1)
		{
			# Read user information from the table
			$key = $dc->get_key($MAIL);

			if ($key ne "")
			{
				($dbh, $errstr) = DB::openOracleConnection();
				if( !$dbh )
				{
					$dc->error("[score] Error connecting to database: $errstr", $errorURL);
				}

				($errN, $errstr, @row) = DB::getRow_UserByUK( $dbh, $dc->DBaseTable('USER'), $key );
				if ($errN)
				{
					$dc->error("[score] Fetching user key: $errN .... $errstr", $errorURL);
				}

				DB::closeOracleConnection( $dbh );

				$dc->q->param('NAME', $row[$dc->UserOff('NAME')]);		# Name
				$dc->q->param('CITY', $row[$dc->UserOff('CITY')]);		# City
				$dc->q->param('STATE', $row[$dc->UserOff('STATE')]);	# State
				$dc->q->param('COUNTRY', $row[$dc->UserOff('COUNTRY')]);# Country
				$dc->q->param('MAIL', $row[$dc->UserOff('MFLAG')]);		# Message Flag
			}
			else
			{
				$dc->q->param('NAME', "");		# Name
				$dc->q->param('CITY', "");		# City
				$dc->q->param('STATE', "");		# State
				$dc->q->param('COUNTRY', "");	# Country
			}

			# Set default to No
			if ($dc->q->param('MAIL') ne 'Y')
			{
				$dc->q->param('MAIL', 'N');
			}
		}
		else
		{
			if($dc->q->param('NAME') eq "") {
				$Warning .= "Oops, you forgot to tell us your name!<BR>";
				$dc->q->param('command', 'form');
			}
			$dc->q->param('NAME', $dc->smut_check($dc->q->param('NAME')));

			if($dc->q->param('CITY') eq "") {
				$Warning .= "Your city was not entered.<BR>";
				$dc->q->param('command', 'form');
			}
			$dc->q->param('CITY', $dc->smut_check($IN::CITY));

			if($IN::COUNTRY eq "") {
				$Warning .= "Your country was not entered.<BR>";
				$dc->q->param('command', 'form');
			}

			if (($IN::COUNTRY eq "US") && ($IN::STATE eq "")) {
				$Warning .= "State must be entered if from the Unitied States.<BR>";
				$dc->q->param('command', 'form');
			} elsif (($IN::COUNTRY ne "US") && ($IN::STATE ne "")) {
				$Warning .= "You must not select a state if your country is not the United States.<BR>";
				$dc->q->param('command', 'form');
			}

			if($IN::MAIL ne "Y") {
				$dc->q->param('MAIL','N');
			}
		}

		my $trunc = substr($dc->q->param('COMMENT'),0,127);
		$dc->q->param('COMMENT', $dc->smut_check($trunc));

		# Set up the error message
		$dc->q->param('Warning', $Warning);
	}
}

#------------------------------------------------
# Depending on Emblem Acquisition
# Routine for Handing Over Jewel Chao 
#------------------------------------------------
sub Count_Emblems {

    # Count the Number of Emblem Acquisitions 
    my $EmblemCount=0;
	my ($i, $j, $val);

    for($i=644;$i<661;$i++) {
        $val=$BINDATA[$i];
        for($j=0;$j<8;$j++) {
            if($val & 1) {
                $EmblemCount++;
            }
            $val >>= 1;
        }
    }
	return ($EmblemCount);
}

#--------------------------------------------------------
# Additional New Data
#--------------------------------------------------------
sub new_record {
	my $UserKey = shift;

	# Record data into Database
	my ($dbh, $errN, $errstr, @row, $newentry);
					
	($dbh, $errstr) = DB::openOracleConnection();
	if( !$dbh )
	{
	$dc->error("[score] Error connecting to database: $errstr");
	}

	# Retrieve Awards
	($errN, $errstr, @row) = DB::getRow_UserByUK( $dbh, $dc->DBaseTable('USER'), $UserKey );
	if ($errN)
	{
		$dc->error("[score] Fetching user Info: $errN .... $errstr", $errorURL);
	}
				
	$dc->q->param('EMBLEMS', $row[$dc->UserOff('EMBLEMS')]);
	$dc->q->param('GOLD', $row[$dc->UserOff('GOLD')]);
	$dc->q->param('SILVER', $row[$dc->UserOff('SILVER')]);
	$dc->q->param('BRONZE', $row[$dc->UserOff('BRONZE')]);
	$dc->q->param('BLUERIB', $row[$dc->UserOff('BLUERIB')]);
				
	# Update user table information
	($errN, $errstr, @oldDATA) = DB::getRow_WRankByUKandEVENT( $dbh, $dc->DBaseTable('WRANK'), $UserKey, $EventID );
	if ($errN)
	{
		$dc->error("[score] Fetching WRank info: $errN .... $errstr", $errorURL);
	}
	
	if ($oldDATA[$dc->WRankOff('KEY')] ne $UserKey)
	{
		# New Record so go ahead and store it
		$newentry = 1;

		($errN, $errstr)       = DB::insertRow_WRank( $dbh, $dc->DBaseTable('WRANK'), $UserKey, $EventID, $Type, $Stage, $Chara, $ftype, $value, $dc->q->param('COMMENT'), time );
		if ($errN)
		{
			$dc->error("[score] Unable to create WRank info: $errN .... $errstr", $errorURL);
		}
	}
	else
	{
		$newentry = 0;

		# First need to see if the current time is better than the one already stored
		if (($oldDATA[$dc->WRankOff('VALUE')] > $value) && ($Type == 0) &&
			(${Chara} ne 'E102')) {
			# Renew Data for Time Attack
			$newentry = 1;
		} elsif (($oldDATA[$dc->WRankOff('VALUE')] < $value) && ($Type == 0) &&
			(${Chara} eq 'E102')) {
			# Renew Data for Time Attack
			$newentry = 1;
		} elsif (($oldDATA[$dc->WRankOff('VALUE')] < $value) && ($Type == 1)) {
			# Renew Data for Score Attack
			$newentry = 1;
		} elsif (($oldDATA[$dc->WRankOff('VALUE')] < $value) && ($Type == 2)) {
			# Renew Data for Fish Weight Attack
			$newentry = 1;
		} elsif ($Type == 3)
		{
			if ($oldDATA[$dc->WRankOff('FTYPE')] < $ftype)
			{
				# Renew Data for Emblem Ranking
				$newentry = 1;
			}
			elsif ($oldDATA[$dc->WRankOff('VALUE')] > $value)
			{
				# Renew Data for Emblem Ranking
				$newentry = 1;
			}
		} elsif ((int($oldDATA[$dc->WRankOff('VALUE')]) > int($value)) && ($Type == 4)) {
			# shilpa changed < to > in above if.
			# Renew Data for Circuit Racing Attack
			$newentry = 1;
		}

		# If so then modify existing record
		if ($newentry == 1)
		{
			($errN, $errstr)       = DB::modifyRow_WRankByUKandEVENT( $dbh, $dc->DBaseTable('WRANK'), $UserKey, $EventID, $Type, $Stage, $Chara, $ftype, $value, $dc->q->param('COMMENT'), time );
			if ($errN)
			{
				$dc->error("[score] Unable to modify WRank info: $errN .... $errstr", $errorURL);
			}
		}
	}

	DB::closeOracleConnection( $dbh );

	return ($newentry);
}

#------------------------------------------------
# Determine what your ranking is
#------------------------------------------------
sub determine_rank {
	my $UserKey = shift;
	my $EventID = shift;
	my $mode = shift;

	my ($dbh, $sth, $errN, $errstr, @row, $key, $adminkey);
	my $rank = 0;
	my $currank = 0;
	my $searchtime = 0;
					
	# Read user information from the table
	# Administration name uses completely unique and illegal characters so it can't be duplicated
	$adminkey = $dc->get_key($dc->DBaseTable('ADMIN'));
		
	($dbh, $errstr) = DB::openOracleConnection();
	if( !$dbh )
	{
		$dc->error("[admin_wrank] Error connecting to database: $errstr");
	}

	if ($mode eq "TODAY")
	{
		$searchtime = (24*60*60);
	}
	else
	{
		# 5 Years in seconds
		$searchtime = (5*365*24*60*60);
	}

	if ($Type == 3)
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEVENTandFTYPE( $dbh, $dc->DBaseTable('WRANK'), $EventID, $searchtime  );
		if ($errN)
		{
			$dc->error("[score] Unable to get Emblem Events: $errN .... $errstr", $errorURL);
		}
	}
	elsif (($Type == 2) || ($Type == 1) || (($Type == 0) && ($Chara eq 'E102')))
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEvent( $dbh, $dc->DBaseTable('WRANK'), $EventID, "DESC", $searchtime  );
		if ($errN)
		{
			$dc->error("[score] Unable to get Descending Events: $errN .... $errstr", $errorURL);
		}
	}
	else
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEvent( $dbh, $dc->DBaseTable('WRANK'), $EventID, "ASC", $searchtime  );
		if ($errN)
		{
			$dc->error("[score] Unable to get Ascending Events: $errN .... $errstr", $errorURL);
		}
	}

    while( (@row) = DB::getNextRow_WRank($sth) )
	{
		$key = $row[$dc->WRankOff('KEY')];
		if (($key ne "") && ($key ne $adminkey))
		{
			++$rank;
			if ($key eq $UserKey)
			{
				$currank = $rank;
			}
		}
	}

	DB::closeOracleConnection( $dbh );

	# Side effect is total number of records have been read
	$MaxRec = $rank;

	return ($currank);
}

#------------------------------------------------
# Will give out special download present
#------------------------------------------------
sub present {
	my $mypresent = shift;

	my ($dbh, $sth, $errN, $errstr, @row, $key);

	$mypresent = sprintf "%d", $mypresent;

	# See if a voice file is available
	if ($mypresent >= 0)
	{
		$key = $dc->get_key($dc->q->param('mailid'));

		if ($key ne "")
		{
			($dbh, $errstr) = DB::openOracleConnection();
			if( !$dbh )
			{
				$dc->error("[score] Error connecting to database: $errstr", $errorURL);
			}

			($errN, $errstr, $sth) = DB::getRow_SurveyByUK( $dbh, $dc->DBaseTable('SURVEY'), $key );
			if ($errN)
			{
				$dc->error("[score] Fetching Survey Information: $errN .... $errstr", $errorURL);
			}
			(@row) = DB::getNextRow_Survey($sth);

			DB::closeOracleConnection( $dbh );

			# ------------ Routine is commented out until Survey.cgi is written -------------
			if (0)
#			if ($row[$dc->SurveyOff('KEY')] ne $key)
			{
				# User has not participated in Survey
				my $opt = "mailid=".$dc->q->param('mailid')."&present=".$mypresent;
				print <<EOF;
We have a gift for you!<BR>
But you must <A HREF="/cgi-bin/soa/sonicadv/survey.cgi?$opt">participate in the survey</A> first.<BR>
EOF
			} else {
				print "We have a gift for you!<BR>";
				if($mypresent == 0) {
					print "<A HREF=\"/gift/gift_sonic.html\">Click here to download the Sonic Voice file!</A>.";
				} elsif ($mypresent == 1) {
					print "<A HREF=\"/gift/gift_tails.html\">Click here to download the Tails Voice file!</A>.";
				} elsif ($mypresent == 2) {
					print "<A HREF=\"/gift/gift_knuckles.html\">Click here to download the Knuckles Voice file!</A>.";
				} elsif ($mypresent == 3) {
					print "<A HREF=\"/gift/gift_amy.html\">Click here to download the Amy Voice file!</A>.";
				} elsif ($mypresent == 4) {
					print "<A HREF=\"/gift/gift_e102.html\">Click here to download the E-102 Gamma Voice file!</A>.";
				} elsif ($mypresent == 5) {
					print "<A HREF=\"/gift/gift_big.html\">Click here to download the Big Voice file!</A>.";
				} elsif ($mypresent == 6) {
					print "<A HREF=\"/gift/gift_robotnik.html\">Click here to download the Dr. Robotnik Voice file!</A>.";
				} elsif ($mypresent == 7) {
					print "<A HREF=\"/gift/gift_tikal.html\">Click here to download the Tikal Voice file!</A>.";
				} elsif ($mypresent == 8) {
					print "<A HREF=\"/gift/gift_all.html\">Click here to download the All Voices file!</A>.";
				}
				print "<BR>\n";
			}
		}
	}
}

#------------------------------------------------
# Decode
#------------------------------------------------
sub decode {
    my $srcdata = shift;

	my $errorNum = 0;
	my $i;

    my (@XOR_CODE) = (65,84,69,90);     # 0x5A455441
    my (@PLUS_VAL) = (65,78,65,78);     # 0x4E414E41

    # BASE64Decode
    @BINDATA = $dc->decode_base64($srcdata);

    my @tmp_val = (0,0,0,0);
    for(my $i=0;$i<313;$i++) {
        my $tmp_val2 = 0;
        for(my $j=0;$j<4;$j++) {
            $BINDATA[$i*4+$j] ^= ($tmp_val[$j] ^ $XOR_CODE[$j]);
            $tmp_val[$j] = ($tmp_val[$j] + $PLUS_VAL[$j] + $tmp_val2);
            $tmp_val2 = $tmp_val[$j]>>8;
            $tmp_val[$j] &= 255;
        }
    }
 
    my $CRC = ($BINDATA[1]<<8)+$BINDATA[0];	
    # if($CRC != $dc->crc(\@BINDATA)) {		
        # $dc->error("CRC Check Error!<BR>World Ranking data is corrupted.", $errorURL);
		# $errorNum = 1;
    # }

    my $DATA_ID = sprintf "%02X%02X%02X%02X",$BINDATA[7],$BINDATA[6],$BINDATA[5],$BINDATA[4];
    if($DATA_ID ne 'C3DDBDB3') {
        $dc->error("Something wrong with World Ranking data ID.\"$DATA_ID\"", $errorURL);
		$errorNum = 1;
    }

    for($i=8;$i<68;$i++) {
        $PDATA .= pack("c",$BINDATA[$i]);
    }
    $WRANK = "";
    for($i=68;$i<1252;$i++) {
        $WRANK .= pack("c",$BINDATA[$i]);
    }

    return($errorNum);
}

#--------------------------------------------------------
# Result Output
#--------------------------------------------------------
sub output_verify {
	my $newRecord = shift;

	my $AdxFile = $dc->q->param('AdxFile');

    print "Content-type: text/html\n\n";
    print <<EOF;

<html>
<head>
<title>
Sonic Adventure Online - World Ranking Validation
</title>
<meta name="x-uirequest" content="urlbaroff">
<script LANGUAGE = "JavaScript">
<!--
        if (document.images) {
            img1on = new Image(); 
            img1on.src = "file:/button_back_on.gif";   
            img1off = new Image(); 
            img1off.src = "file:/button_back.gif"; 
        }

function imgOn(imgName) {
        if (document.images) {
            document[imgName].src = eval(imgName + "on.src");
        }
}

function imgOff(imgName) {
        if (document.images) {
            document[imgName].src = eval(imgName + "off.src");
        }
}

// -->
</script>
<BGSOUND SRC="$AdxFile">
</head>
<body x-marginleft=0 x-margintop=0   background="file:/bg_scroller.gif" bgcolor="#000000" marginheight=0 marginwidth=0 topmargin=0 leftmargin=0>
<center>
<img src="file:/blank_dot.gif" width=1 height=30 border=0 alt=""><br>
<table cellspacing=0 cellpadding=5 border=0 width=590><tr><td align=center valign=top bgcolor="#000033"><table cellspacing=0 cellpadding=0 border=0 width=580><tr><td align=left valign=top bgcolor="#ffffff">

<!-- HEADER IMAGE -->
<!-- choose from below... -->
<!-- header_chao_showoff.gif -->
<!-- header_events.gif -->
<!-- header_world_rankings.gif -->

<img src="file:/header_world_rankings.gif" width=580 height=150 border=0 alt=""><br>

<!-- END HEADER IMAGE -->

<table cellspacing=0 cellpadding=0 border=0 width=580><tr><td align=left valign=top width="10">
<img src="file:/blank_dot.gif" width=10 height=1 border=0 alt="">
</td>
<td align=left valign=top width=560>

<!-- BEGIN CONTENT HERE -->
EOF
	if ($newRecord == 1)
	{
		print "Congratulations!<p>\n\n";

	}
	else
	{
		my $ftype = $oldDATA[$dc->WRankOff('FTYPE')];
		my $value = $oldDATA[$dc->WRankOff('VALUE')];

		if ($Type == 0)
		{
			print "The new time of ".$dc->q->param('Score')." will not be recorded <BR>\n";
			print "because your previous time was faster.<BR>\n";
			print "Here is your current record:<p>\n";

			$dc->q->param('Score', $dc->calc_int_time($value));
		}
		elsif ($Type == 1)
		{
			print "The new score of ".$dc->q->param('Score')." will not be recorded<BR>\n";
			print "because your previous score was higher.<BR>\n";
			print "Here is your current record:<p>\n";

			$dc->q->param('Score', sprintf " %d",
				$value);
		}
		elsif ($Type == 2)
		{
			print "The new catch of ".$dc->q->param('Score')." will not be recorded<BR>\n";
			print "because your previous catch was heavier.<BR>\n";
			print "Here is your current record:<p>\n";

			$dc->q->param('Score', sprintf " %d grams",
				$value);
			$dc->q->param('CharaName', $SakanaName[$ftype]);
		}
		elsif ($Type == 3)
		{
			print "The new emblem count of ".$dc->q->param('Score')." emblems in ".$dc->q->param('CharaName')." will not be recorded \n";
			print "because your previous emblem count was higher, \n";
			print "and/or your previous time was faster.<BR>\n";
			print "Here is your current record:<p>\n";

			$dc->q->param('Score', $ftype);
			$dc->q->param('CharaName', sprintf " %d : %02d . %02d",
				int($value/216000),
				int(($value%216000)/3600),
				int(($value%60)*1.66));
		}
		elsif ($Type == 4)
		{
			print "The new time of ".$dc->q->param('Score')." will not be recorded <BR>\n";
			print "because your previous time was faster.<BR>\n";
			print "Here is your current record:<p>\n";

			$dc->q->param('Score', sprintf " %d : %02d . %02d",
					int(substr($value, -6, 2)),
					int(substr($value, -4, 2)),
					int(substr($value, -2, 2)));
		}


		$dc->q->param('COMMENT', $oldDATA[$dc->WRankOff('COMMENT')]);
	}

	print "You place #$allrank in World Rankings!<br>\n";
	print "You place #$todayrank in Today's Rankings!<p>\n";

	print <<EOF;
<CENTER>
<TABLE border=0 cellpadding=5 cellspacing=0 width=560 BGCOLOR="#CCCCCC">
<TR>
<TD BGCOLOR="#666666"><FONT COLOR="#ffffff"></FONT></td>
<td align=left valign=top colspan=3 bgcolor="#666666">
<FONT COLOR="#ffffff">
EOF

	if ($Type == 2)
	{
		print "Big";
	}
	else
	{
		print $dc->q->param('CharaName');
	}
	print " in ".$dc->q->param('StageName')."<br>";

	print $dc->q->param('GameType')." Attack: ".$dc->q->param('Score')." ";
	if ($Type == 2)
	{
		print $dc->q->param('CharaName');
	}

	print <<EOF;
</FONT></TD>
</TR>
<TR><TD valign=top width=60>
EOF

	if ($dc->Flags($IN::COUNTRY) ne "")
	{
		print "<img src=\"/images/flags/".$dc->Flags($IN::COUNTRY)."\" width=40 height=20 border=0>";	
	} else {
		# Draw the generic flag
		print "<img src=\"/images/flags/flag_other.gif\" width=40 height=20 border=0>";
	}

	print "</TD><td align=left valign=middle colspan=2>";
	print $dc->q->param('NAME')."<BR>\n";

	if ($dc->q->param('MAIL') eq "Y")
	{
		print "</TD><TD VALIGN=\"top\" ALIGN=\"right\">".$dc->q->param('mailid')."</TD></TR>\n";
	} else {
		print "</TD><TD VALIGN=\"top\" ALIGN=\"right\">Hidden</TD></TR>\n";
	}

	print "<TR><TD><BR></TD><td align=left valign=top colspan=3>".$dc->q->param('CITY').", ";
	if ($dc->q->param('STATE') ne "") {
		printf "%s, ", $dc->state_name($dc->q->param('STATE'));
	}
	printf "%s\n", $dc->country_name($dc->q->param('COUNTRY'));


	print <<EOF;
</TR>
<TR><TD valign=top width=60 bgcolor="#dddddd">
EOF
	if ($allrank == 1)
	{
		print "<img src=\"/images/wrank/gold_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}
	elsif ($allrank == 2)
	{
		print "<img src=\"/images/wrank/silver_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}
	elsif ($allrank == 3)
	{
		print "<img src=\"/images/wrank/bronze_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}
	elsif ($todayrank == 1)
	{
		print "<img src=\"/images/wrank/flag_1_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}
	elsif ($todayrank == 2)
	{
		print "<img src=\"/images/wrank/flag_2_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}
	elsif ($todayrank == 3)
	{
		print "<img src=\"/images/wrank/flag_3_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
	}


	print "</TD><TD colspan=\"3\" BGCOLOR=\"#DDDDDD\">Awards:<br>\n";
	my $count = 0;
	my $loop;

	if ($dc->q->param('EMBLEMS') == 130)
	{
		# User gets emblem award if has all 130
		print "<img src=\"/images/wrank/emblem_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		++$count;
	}

	for ($loop = 0; $loop < $dc->q->param('GOLD'); ++$loop)
	{
		print "<img src=\"/images/wrank/gold_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		++$count;
		if ($count >= 8)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=5 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $dc->q->param('SILVER'); ++$loop)
	{
		print "<img src=\"/images/wrank/silver_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		++$count;
		if ($count >= 8)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=5 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $dc->q->param('BRONZE'); ++$loop)
	{
		print "<img src=\"/images/wrank/bronze_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		++$count;
		if ($count >= 8)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=5 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $dc->q->param('BLUERIB'); ++$loop)
	{
		print "<img src=\"/images/wrank/ribbon_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		++$count;
		if ($count >= 8)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=5 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	print "<p>\nComments:<BR>";
	print $dc->q->param('COMMENT');

	print <<EOF;
</TD></TR>
</TABLE>
</CENTER>
&nbsp;<BR>
EOF

	&present($present);

	print <<EOF;
<!-- END CONTENT HERE -->
&nbsp;<br>
<a href="/world_rankings.html"  onMouseOver="imgOn('img1')" onMouseOut="imgOff('img1')"><img src="file:/button_back.gif" width=81 height=24 border=0 alt="" name="img1"></a><P>				
</td><td align=left valign=top width="10">
<img src="file:/blank_dot.gif" width=10 height=1 border=0 alt="">
</td>
</tr>
</table>
</tr>
</tr>
</table>
</td>
</tr>
</table>
<br>&nbsp;
</center>
</body>
</html>
EOF

}

######################################################################
# Display contents of World Rankings
######################################################################

#--------------------------------------------------------
# Data Check
#--------------------------------------------------------
sub check_search {
	my ($errN, $errstr, $dbh, $sth, @wrank);
	my ($Assort, $Stage, $Chara, $val);

	$dc->q->param('message', "You can search for rankings here. Search by Email or go through the ranks.  ");

	if($IN::max ne "") {
		$MAX = $IN::max;
		if($MAX<=0) {
			# Set default maximum size
			$MAX=10;
		}
	}
		
	$START=0;
	if($IN::start ne "") {
		$START = ($IN::start - 1);
		if($START<0) {
			$START=0;
		}
	}

	# Save original Maximum Record value
	my $OldMax = $MaxRec;

	# Determine total number of records for All time and Today
	&determine_rank("", $EventID, "ALL");
	$dc->q->param("maxall", $MaxRec);
	&determine_rank("", $EventID, "TODAY");
	$dc->q->param("maxtoday", $MaxRec);

	# Restore original Maximum Records value
	$MaxRec = $OldMax;

	#Initialize base values
	$dc->q->param('max', $MAX);
	$dc->q->param('start', $START + 1);

	if ($IN::mode eq "TODAY") {
		$mode = "TODAY";
	} else {
		$mode = "ALL";
		$dc->q->param('mode', "ALL");
	}
		
	if($IN::mailid ne "") {
		$UserKey = $dc->get_key($IN::mailid);
		if ($UserKey eq "")
		{
			$dc->q->param('message', "<font color=\"#ff0000\">Sorry, no matches were found containing <b>$IN::mailid</b>.</font><p>Please try again. ");
		
			# Terminate the search
			$dc->output_form("html/rank_search.html");
			undef($UserKey);
			exit(0);
		}
		else
		{
			($dbh, $errstr) = DB::openOracleConnection();
			if( !$dbh )
			{
				$dc->error("[score] Error connecting to database: $errstr", $errorURL);
			}

		    ($errN, $errstr, @wrank) = DB::getRow_WRankByUKandEVENT( $dbh, $dc->DBaseTable('WRANK'), $UserKey, $EventID );
			if ($errN)
			{
				$dc->error("[score] Fetching user info: $errN .... $errstr", $errorURL);
			}

			DB::closeOracleConnection( $dbh );

			if (($wrank[$dc->WRankOff('KEY')] ne $UserKey))
			{
				$dc->q->param('message', "<font color=\"#ff0000\">Sorry, no matches were found containing <b>$IN::mailid</b>.</font><p>Please try again. ");

				# Terminate the search
				$dc->output_form("html/rank_search.html");
				undef($UserKey);
				exit(0);
			}
		}
	}
}

#--------------------------------------------------------
# Read Key Data
#--------------------------------------------------------
sub read_data {
	my $key = shift;
	my ($errN, $errstr, $dbh, $sth, @row);

	($dbh, $errstr) = DB::openOracleConnection();
	if( !$dbh )
	{
		$dc->error("[score] Error connecting to database: $errstr", $errorURL);
	}

	if($UserKey eq "") {
		# Calculate the maximum number of records
		&determine_rank("", $EventID, $dc->q->param('mode'));

		if($START < $MaxRec) {
			if(($MaxRec-$START)>($MAX)) {
				$END=$START+$MAX;
				$nextflag=0;
			} else {
				$END=$MaxRec;
				$nextflag=1;
			}
		}
	}

	return $dbh;
}

#--------------------------------------------------------
# HTML Output
#--------------------------------------------------------
sub output_records {
	my $dbh = shift;

	my ($errN, $errstr, $sth, @user, @wrank);
	my $loop = 0;
	my $adminkey = $dc->get_key($dc->DBaseTable('ADMIN'));
	my $AdxFile = $dc->q->param('AdxFile');
	my $searchtime = 0;

    print "Content-type: text/html\n";
    print <<EOF;

<html>
<head>
<title>
Sonic Adventure Online - Time Attack
</title>
<meta name="x-uirequest" content="urlbaroff">
<script LANGUAGE = "JavaScript">
<!--
        if (document.images) {
            img1on = new Image(); 
            img1on.src = "file:/button_back_on.gif";   
            img1off = new Image(); 
            img1off.src = "file:/button_back.gif"; 
        }

function imgOn(imgName) {
        if (document.images) {
            document[imgName].src = eval(imgName + "on.src");
        }
}

function imgOff(imgName) {
        if (document.images) {
            document[imgName].src = eval(imgName + "off.src");
        }
}
// -->

</script>
<BGSOUND SRC="$AdxFile">
</head>
<body x-marginleft=0 x-margintop=0   background="file:/bg_scroller.gif" bgcolor="#000000" marginheight=0 marginwidth=0 topmargin=0 leftmargin=0>
<center>
<img src="file:/blank_dot.gif" width=1 height=30 border=0 alt=""><br>
<table cellspacing=0 cellpadding=5 border=0 width=590><tr><td align=center valign=top bgcolor="#000033"><table cellspacing=0 cellpadding=0 border=0 width=580><tr><td align=left valign=top bgcolor="#ffffff">

<!-- HEADER IMAGE -->
<!-- choose from below... -->
<!-- header_chao_showoff.gif -->
<!-- header_events.gif -->
<!-- header_world_rankings.gif -->

<img src="file:/header_world_rankings.gif" width=580 height=150 border=0 alt=""><br>

<!-- END HEADER IMAGE -->

<table cellspacing=0 cellpadding=0 border=0 width=580><tr><td align=left valign=top width="10">
<img src="file:/blank_dot.gif" width=10 height=1 border=0 alt="">
</td>
<td align=left valign=top width=560>

<!-- BEGIN CONTENT HERE -->
EOF

	print "<p>".$dc->q->param('GameType')." rankings for ".$dc->q->param('CharaName')." in ".$dc->q->param('StageName').".<BR>";

	print <<EOF;
What is your ranking?
<p>
<a href="#bottom">BOTTOM</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
EOF

	if ($UserKey eq "")
	{
		&output_link;
	}

	print "<br><img src=\"file:/blank_dot.gif\" height=\"10\" width=\"1\"><br>";
	
	if ($dc->q->param('mode') eq "TODAY")
	{
		$searchtime = (24*60*60);
	}
	else
	{
		# 5 Years in seconds
		$searchtime = (5*365*24*60*60);
	}

	if ($Type == 3)
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEVENTandFTYPE( $dbh, $dc->DBaseTable('WRANK'), $EventID, $searchtime );
		if ($errN)
		{
			$dc->error("[score] Unable to get Emblem Events: $errN .... $errstr", $errorURL);
		}
	}
	elsif (($Type == 2) || ($Type == 1) || (($Type == 0) && ($Chara eq 'E102')))
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEvent( $dbh, $dc->DBaseTable('WRANK'), $EventID, "DESC", $searchtime );
		if ($errN)
		{
			$dc->error("[score] Unable to get Descending Events: $errN .... $errstr", $errorURL);
		}
	}
	else
	{
		($errN, $errstr, $sth) = DB::getRow_WRankByEvent( $dbh, $dc->DBaseTable('WRANK'), $EventID, "ASC", $searchtime );
		if ($errN)
		{
			$dc->error("[score] Unable to get Ascending Events: $errN .... $errstr", $errorURL);
		}
	}

	if($UserKey ne "") {
		my $Rank = 0;
	    while( (@wrank) = DB::getNextRow_WRank($sth) )
		{
			if ($wrank[$dc->WRankOff('KEY')] eq $adminkey)
			{
				#Skip that record since it is the Admin record
				(@wrank) = DB::getNextRow_WRank($sth);
			}

			if ($wrank[$dc->WRankOff('KEY')] eq $UserKey)
			{
				($errN, $errstr, @user) = DB::getRow_UserByUK( $dbh, $dc->DBaseTable('USER'), $UserKey );
				if ($errN)
				{
					$dc->error("[score] Fetching user info: $errN .... $errstr", $errorURL);
				}
				&build_table($Rank, \@user, \@wrank);
			}
			++$Rank;
		}
	} else {
		for($loop=0;$loop<$END;$loop++) {
			(@wrank) = DB::getNextRow_WRank($sth);
			if ($wrank[$dc->WRankOff('KEY')] eq $adminkey)
			{
				#Skip that record since it is the Admin record
				(@wrank) = DB::getNextRow_WRank($sth);
			}
			if ($loop >= $START)
			{
				($errN, $errstr, @user) = DB::getRow_UserByUK( $dbh, $dc->DBaseTable('USER'), $wrank[$dc->WRankOff('KEY')] );
				if ($errN)
				{
					$dc->error("[score] Fetching user info: $errN .... $errstr", $errorURL);
				}
				&build_table($loop, \@user, \@wrank);
			}
		}
	}

	DB::closeOracleConnection( $dbh );

	if ($UserKey eq "")
	{
		&output_link;
		print "&nbsp;<BR>\n";
	}

    print <<EOF;
<!-- END CONTENT HERE -->
&nbsp;<BR>
<a name="bottom"></a><a href="/world_rankings.html"  onMouseOver="imgOn('img1')" onMouseOut="imgOff('img1')"><img src="file:/button_back.gif" width=81 height=24 border=0 alt="" name="img1"></a><P>				
</td><td align=left valign=top width="10">
<img src="file:/blank_dot.gif" width=10 height=1 border=0 alt="">
</td>
</tr>
</table>
</tr>
</tr>
</table>
</td>
</tr>
</table>
<br>&nbsp;
</center>
</body>
</html>
EOF

}

sub build_table {
	my $rank = shift;
	my $user = shift;
	my $wrank = shift;

	print "<TABLE border=0 cellpadding=5 cellspacing=0 width=560 bgcolor=\"#CCCCCC\">\n";
	print "<TR>\n";
	printf "<TD BGCOLOR=\"#666666\"><FONT COLOR=\"#ffffff\">%d.</FONT></TD>\n",$rank+1;
	if ($Type == 0) {
		printf "<td align=left valign=top colspan=3 bgcolor=\"#666666\"><FONT COLOR=\"#ffffff\">%s </FONT></TD>\n",
		 $dc->calc_int_time($wrank->[$dc->WRankOff('VALUE')]);
	} elsif ($Type == 1) {
		printf "<td align=left valign=top colspan=3 bgcolor=\"#666666\"><FONT COLOR=\"#ffffff\">%d points</FONT></TD>\n",$wrank->[$dc->WRankOff('VALUE')];
	} elsif ($Type == 2) {
		printf "<td align=left valign=top colspan=3 bgcolor=\"#666666\"><FONT COLOR=\"#ffffff\">%d gram %s</FONT></TD>\n",$wrank->[$dc->WRankOff('VALUE')], $SakanaName[$wrank->[$dc->WRankOff('FTYPE')]];
	} elsif ($Type == 3) {
		printf "<td align=left valign=top colspan=3 bgcolor=\"#666666\"><FONT COLOR=\"#ffffff\">%d emblems in %d hours, %02.2d minutes</FONT></TD>\n",
		$wrank->[$dc->WRankOff('FTYPE')],
		int($wrank->[$dc->WRankOff('VALUE')]/216000),
		int(($wrank->[$dc->WRankOff('VALUE')]%216000)/3600);
	} elsif ($Type == 4) {
		printf "<td align=left valign=top colspan=3 bgcolor=\"#666666\"><FONT COLOR=\"#ffffff\">%d : %02.2d . %02.2d</FONT></TD>\n", 
					int(substr($wrank->[$dc->WRankOff('VALUE')], -6, 2)),
					int(substr($wrank->[$dc->WRankOff('VALUE')], -4, 2)),
					int(substr($wrank->[$dc->WRankOff('VALUE')], -2, 2));
	#shilpa changed above lines.
		#int($wrank->[$dc->WRankOff('VALUE')]/3600),
		#int(($wrank->[$dc->WRankOff('VALUE')]%3600)/60),
		#int(($wrank->[$dc->WRankOff('VALUE')]%60)*1.66);
	}
	print "</TR>\n<TR>\n";
	if ($dc->Flags($user->[$dc->UserOff('COUNTRY')]) ne "")
	{
		print "<TD valign=top width=60><img src=\"/images/flags/".$dc->Flags($user->[$dc->UserOff('COUNTRY')])."\" width=40 height=20 border=0></TD>\n";	
	} else {
		# Draw the generic flag
		print "<TD valign=top width=60><img src=\"/images/flags/flag_other.gif\" width=40 height=20 border=0></TD>\n";
	}
	print "<td align=left valign=middle colspan=2>$user->[$dc->UserOff('NAME')]<br>\n";
	print "$user->[$dc->UserOff('CITY')], ";
	if ($user->[$dc->UserOff('STATE')] ne "") {
		printf "%s, ", $dc->state_name($user->[$dc->UserOff('STATE')]);
	}
	printf " %s</TD>\n", $dc->country_name($user->[$dc->UserOff('COUNTRY')]);
	if($user->[$dc->UserOff('MFLAG')] eq "Y") {
		print "<TD width=40 ALIGN=\"right\"><A HREF=\"mailto:$user->[$dc->UserOff('EMAIL')]\"><IMG src=\"file:/icon_mail.gif\" border=0></A></TD>\n";
	} else {
		print "<TD width=40 ALIGN=\"right\"><BR></TD>\n";
	}
	print "</TR>\n";

	print "<TR><TD valign=top width=60 bgcolor=\"#dddddd\">";
	if ($dc->q->param('mode') eq "TODAY")
	{
		if ($rank == 0)
		{
			print "<img src=\"/images/wrank/flag_1_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
		elsif ($rank == 1)
		{
			print "<img src=\"/images/wrank/flag_2_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
		elsif ($rank == 2)
		{
			print "<img src=\"/images/wrank/flag_3_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
	}
	else
	{
		if ($rank == 0)
		{
			print "<img src=\"/images/wrank/gold_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
		elsif ($rank == 1)
		{
			print "<img src=\"/images/wrank/silver_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
		elsif ($rank == 2)
		{
			print "<img src=\"/images/wrank/bronze_big.gif\" width=50 height=50 border=0 hspace=5 align=\"top\">";
		}
	}

	print "</td><TD colspan=\"3\" BGCOLOR=\"#DDDDDD\">Awards:<br>";

	my $count = 0;
	my $loop;

	if ($user->[$dc->UserOff('EMBLEMS')] == 130)
	{
		# User gets emblem award if has all 130
		print "<img src=\"/images/wrank/emblem_small.gif\" width=25 height=25 border=0 hspace=2 align=\"top\">";
		++$count;
	}

	for ($loop = 0; $loop < $user->[$dc->UserOff('GOLD')]; ++$loop)
	{
		print "<img src=\"/images/wrank/gold_small.gif\" width=25 height=25 border=0 hspace=2 align=\"top\">";
		++$count;
		if ($count >= 16)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=2 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $user->[$dc->UserOff('SILVER')]; ++$loop)
	{
		print "<img src=\"/images/wrank/silver_small.gif\" width=25 height=25 border=0 hspace=2 align=\"top\">";
		++$count;
		if ($count >= 16)
		{
			print "<BR><img src=\"file:/blank_small.gif\" height=2 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $user->[$dc->UserOff('BRONZE')]; ++$loop)
	{
		print "<img src=\"/images/wrank/bronze_small.gif\" width=25 height=25 border=0 hspace=2 align=\"top\">";
		++$count;
		if ($count >= 16)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=2 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	for ($loop = 0; $loop < $user->[$dc->UserOff('BLUERIB')]; ++$loop)
	{
		print "<img src=\"/images/wrank/ribbon_small.gif\" width=25 height=25 border=0 hspace=2 align=\"top\">";
		++$count;
		if ($count >= 16)
		{
			print "<BR><img src=\"file:/blank_dot.gif\" height=2 width=1 border=0><br>\n";
			$count = 0;
		}
	}

	print "\n&nbsp;<BR>\nComments:<BR>$wrank->[$dc->WRankOff('COMMENT')]</TD></TR>\n";
	print "</TABLE>\n";
	print "&nbsp;<BR>\n";
}

sub output_link {
	# Link Menu Output
	my $str = "";
	my $prank = 0;
	my $nrank = 0;
		
	if($START > 0) {
		$prank=$START-$MAX+1;
		if($prank<0) { $prank=0; }
		$str= 'command=view&max=' . $MAX . '&start=' . $prank . '&ASSORT='.$dc->q->param('ASSORT') .
              '&STAGE='.$dc->q->param('STAGE') . '&CHARA='.$dc->q->param('CHARA') . '&mode='. $dc->q->param('mode');
		print "[<A HREF=\"$cgiPath?$str\">Higher Ranks</A>]\n";
	}
	if($nextflag==0) {
		$nrank=$START+$MAX+1;
		$str= 'command=view&max=' . $MAX . '&start=' . $nrank . '&ASSORT='.$dc->q->param('ASSORT') .
              '&STAGE='.$dc->q->param('STAGE') . '&CHARA='.$dc->q->param('CHARA') . '&mode='. $dc->q->param('mode');
		print "[<A HREF=\"$cgiPath?$str\">Lower Ranks</A>]\n";
	}
}

#------------------------ EOF --------------------------
