//AutoPilot script by Gamer_Z v0.2
#include <a_samp>//SA:MP Team
#define FILTERSCRIPT
#include <RouteConnector>//GPS Plugin
#include <zcmd>//By Zeex
////////////////////////////////////////////////////////////////////////////////
//#define USE_TIMERS
#define USE_SMOOTH_TURNS // thanks to richardcor91 for the SetVehicleAngularVelocity help
////////////////////////////////////////////////////////////////////////////////
new id[ MAX_PLAYERS] = { - 1 ,...} ;
new CurrTarget[ MAX_PLAYERS] = { 0 ,...} ;
new Timer[ MAX_PLAYERS] = { - 1 ,...} ;
new Float: spd[ MAX_PLAYERS] = { 0.30 ,...} ;
#if defined USE_TIMERS
new interval[ MAX_PLAYERS] = { 250 ,...} ;
#endif
////////////////////////////////////////////////////////////////////////////////
enum location
{
name[ 16 ] ,
Float: X,
Float: Y,
Float: Z
}
#define PLACES (6)
new places[ PLACES] [ location] =
{
{ "LV-c" ,2140.6675 ,993.1867 ,10.5248 } ,//Las Venturas
{ "SF-c" ,- 2261.2009 ,564.2894 ,34.7200 } ,//San Frierro
{ "LS-c" ,2495.3755 ,- 1669.4906 ,13.5163 } ,//Los Santos
{ "LV-a" ,1686.3107 ,1609.5485 ,10.8203 } ,//Las Venturas Airport
{ "SF-a" ,- 1538.8635 ,- 422.9142 ,5.8516 } ,//San Frierro Airport
{ "LS-a" ,1953.5204 ,- 2290.1130 ,13.5469 } //Los Santos Airport
} ;
////////////////////////////////////////////////////////////////////////////////
CMD: autopilot( playerid,params[ ] )
{
if ( ! IsPlayerInAnyVehicle( playerid) )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT YOU MUST BE IN A VEHICLE" ) ;
return 1 ;
}
if ( ! strcmp ( params,"stop" ,true ) )
{
if ( Timer[ playerid] ! = ( - 1 ) )
{
#if defined USE_TIMERS
KillTimer( Timer[ playerid] ) ;
#endif
Timer[ playerid] = - 1 ;
DeleteArray( id[ playerid] ) ;
id[ playerid] = - 1 ;
CurrTarget[ playerid] = 0 ;
SendClientMessage( playerid,- 1 ,"AUTOPILOT DISABLED" ) ;
return 1 ;
}
SendClientMessage( playerid,- 1 ,"AUTOPILOT COULDN'T BE DISABLED" ) ;
return 1 ;
}
if ( params[ 0 ] == 48 && params[ 1 ] == 46 )
{
if ( id[ playerid] == - 1 )
{
new out[ 32 ] ;
if ( ! isNumeric( params[ 2 ] ) )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT SPEED MUST BE BETWEEN 0.01 and 0.80" ) ;
return 1 ;
}
if ( ! isNumeric( params[ 3 ] ) )
params[ 3 ] = 48 ;
format( out,32 ,"%c%c" ,params[ 2 ] ,params[ 3 ] ) ;
new Float: tmpspd = floatdiv( strval( out) ,100.00 ) ;
if ( 0.01 > tmpspd > 0.80 )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT SPEED MUST BE BETWEEN 0.01 and 0.80" ) ;
return 1 ;
}
spd[ playerid] = tmpspd;
format( out,32 ,"AUTOPILOT SPEED SET TO: %.3f" ,spd[ playerid] ) ;
SendClientMessage( playerid,- 1 ,out) ;
}
else
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT CANNOT CHANGE SPEED WHILE DRIVING (bug prevention)" ) ;
}
return 1 ;
}
if ( id[ playerid] == - 1 )
{
if ( params[ 0 ] == 0 || ( params[ 0 ] == 1 && params[ 1 ] == 0 ) )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT HAS NO TARGET" ) ;
return 1 ;
}
new place = - 1 ;
for ( new i = 0 ; i < PLACES; ++ i)
{
if ( ! strcmp ( places[ i] [ name] ,params,true ) )
{
place = i;
break ;
}
}
if ( place == - 1 )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT DOESN'T KNOW THAT PLACE" ) ;
return 1 ;
}
new start = NearestPlayerNode( playerid,15.0 ) ;
if ( start == - 1 )
{
SendClientMessage( playerid,- 1 ,"AUTOPILOT MALFUNCTION, PLEASE TRY AGAIN ON ANOTHER PLACE" ) ;
return 1 ;
}
CalculatePath( start,NearestNodeFromPoint( places[ place] [ X] ,places[ place] [ Y] ,places[ place] [ Z] ) ,playerid) ;
SendClientMessage( playerid,- 1 ,"AUTOPILOT IS CALCULATING THE ROUTE FOR YOU.." ) ;
return 1 ;
}
SendClientMessage( playerid,- 1 ,"AUTOPILOT ALREADY TURNED ON" ) ;
return 1 ;
}
CMD: ap( playerid,params[ ] )
{
return cmd_autopilot( playerid,params) ;
}
stock isNumeric( const string[ ] )
{
new length= strlen ( string) ;
if ( length== 0 ) return false ;
for ( new i = 0 ; i < length; i++ )
{
if (
( string[ i] > '9' || string[ i] < '0' && string[ i] ! = '-' && string[ i] ! = '+' ) // Not a number,'+' or '-'
|| ( string[ i] == '-' && i! = 0 ) // A '-' but not at first.
|| ( string[ i] == '+' && i! = 0 ) // A '+' but not at first.
) return false ;
}
if ( length== 1 && ( string[ 0 ] == '-' || string[ 0 ] == '+' ) ) return false ;
return true ;
}
#if defined USE_TIMERS
CMD: interval( playerid,params[ ] )
{
interval[ playerid] = strval( params) ;
format( string,128 ,"Interval: %d" ,interval) ;
SendClientMessage( playerid,- 1 ,string) ;
return 1 ;
}
#endif
////////////////////////////////////////////////////////////////////////////////
public GPS_WhenRouteIsCalculated( routeid,node_id_array[ ] ,amount_of_nodes,distance)
{
id[ routeid] = StoreRouteArray( amount_of_nodes,node_id_array) ;
#if defined USE_TIMERS
Timer[ routeid] = SetTimerEx( "AutoPilot" ,interval[ routeid] ,1 ,"i" ,routeid) ;
#else
Timer[ routeid] = 1 ;
#endif
SendClientMessage( routeid,- 1 ,".. AUTOPILOT WILL DRIVE YOU NOW TO YOUR DESTINATION" ) ;
return 1 ;
}
#if defined USE_TIMERS
#else
public OnPlayerUpdate( playerid)
{
if ( Timer[ playerid] == 1 )
AutoPilot( playerid) ;
return 1 ;
}
#endif
public OnPlayerConnect( playerid)
{
Timer[ playerid] = - 1 ;
id[ playerid] = - 1 ;
CurrTarget[ playerid] = 0 ;
#if defined USE_TIMERS
interval[ playerid] = 250 ;
#endif
return 1 ;
}
public OnPlayerDisconnect( playerid,reason)
{
if ( Timer[ playerid] ! = ( - 1 ) )
{
#if defined USE_TIMERS
KillTimer( Timer[ playerid] ) ;
#endif
Timer[ playerid] = - 1 ;
DeleteArray( id[ playerid] ) ;
id[ playerid] = - 1 ;
CurrTarget[ playerid] = 0 ;
}
return 1 ;
}
forward AutoPilot( playerid) ;
public AutoPilot( playerid)
{
if ( IsPlayerInAnyVehicle( playerid) )
{
new Float: pos[ 2 ] [ 3 ] ;
new vehicleid = GetPlayerVehicleID( playerid) ;
if ( CurrTarget[ playerid] == 0 )
{
CurrTarget[ playerid] ++ ;
GetNodePos( GetRouteAtPos( id[ playerid] ,CurrTarget[ playerid] ) ,pos[ 0 ] [ 0 ] ,pos[ 0 ] [ 1 ] ,pos[ 0 ] [ 2 ] ) ;
SetVehiclePos( vehicleid,pos[ 0 ] [ 0 ] ,pos[ 0 ] [ 1 ] ,pos[ 0 ] [ 2 ] + 2.0 ) ;
return 1 ;
}
new amount;
new nodeid = GetRouteAtPos( id[ playerid] ,CurrTarget[ playerid] ,amount) ;
if ( ( CurrTarget[ playerid] + 1 ) >= amount)
{
#if defined USE_TIMERS
KillTimer( Timer[ playerid] ) ;
#endif
Timer[ playerid] = - 1 ;
DeleteArray( id[ playerid] ) ;
id[ playerid] = - 1 ;
CurrTarget[ playerid] = 0 ;
SetVehicleVelocity( vehicleid,0.0 ,0.0 ,0.0 ) ;
SendClientMessage( playerid,- 1 ,"Destination reached, have a nice day." ) ;
return 1 ;
}
GetNodePos( nodeid,pos[ 1 ] [ 0 ] ,pos[ 1 ] [ 1 ] ,pos[ 1 ] [ 2 ] ) ;
if ( IsPlayerInRangeOfPoint( playerid,10.0 ,pos[ 1 ] [ 0 ] ,pos[ 1 ] [ 1 ] ,pos[ 1 ] [ 2 ] ) )
{
CurrTarget[ playerid] ++ ;
return 1 ;
}
PullVehicleIntoDirection( vehicleid,pos[ 1 ] [ 0 ] ,pos[ 1 ] [ 1 ] ,pos[ 1 ] [ 2 ] ,spd[ playerid] ) ;
}
else
{
#if defined USE_TIMERS
KillTimer( Timer[ playerid] ) ;
#endif
Timer[ playerid] = - 1 ;
DeleteArray( id[ playerid] ) ;
id[ playerid] = - 1 ;
CurrTarget[ playerid] = 0 ;
}
return 1 ;
}
//--------------------AUTO-PILOT-CORE-FUNCTIONS-------------------------------//
#define DEPRECATE_Z
stock PullVehicleIntoDirection( vehicleid, Float: x, Float: y, Float: z, Float: speed) //Thanks to Miguel for supplying me with this function, I have edited it a bit
{
new
Float: distance,
Float: vehicle_pos[ 3 ] ;
GetVehiclePos( vehicleid, vehicle_pos[ 0 ] , vehicle_pos[ 1 ] , vehicle_pos[ 2 ] ) ;
#if defined USE_SMOOTH_TURNS
new Float: oz = atan2VehicleZ( vehicle_pos[ 0 ] , vehicle_pos[ 1 ] , x, y) ;
new Float: vz;
GetVehicleZAngle( vehicleid, vz) ;
if ( oz < vz- 180 ) oz = oz+ 360 ;
if ( vz < oz- 180 ) vz = vz+ 360 ;
new Float: cz = floatabs( vz - oz) ;
#else
SetVehicleZAngle( vehicleid, atan2VehicleZ( vehicle_pos[ 0 ] , vehicle_pos[ 1 ] , x, y) ) ;
#endif
x - = vehicle_pos[ 0 ] ;
y - = vehicle_pos[ 1 ] ;
z - = vehicle_pos[ 2 ] ;
#if defined DEPRECATE_Z
distance = floatsqroot( ( x * x) + ( y * y) ) ;
x = ( speed * x) / distance;
y = ( speed * y) / distance;
GetVehicleVelocity( vehicleid, vehicle_pos[ 0 ] , vehicle_pos[ 0 ] , z) ;
#else
z+ = 0.11 ;
distance = floatsqroot( ( x * x) + ( y * y) + ( z * z) ) ;
x = ( speed * x) / distance;
y = ( speed * y) / distance;
z = ( speed * z) / distance;
#endif
#if defined USE_SMOOTH_TURNS
if ( cz > 0 )
{
new Float: fz = cz* 0.0015 ;
if ( vz < oz) SetVehicleAngularVelocity( vehicleid, 0.0 , 0.0 , fz) ;
if ( vz > oz) SetVehicleAngularVelocity( vehicleid, 0.0 , 0.0 , - fz) ;
}
#endif
SetVehicleVelocity( vehicleid, x, y, z) ;
}
forward Float: atan2VehicleZ( Float: Xb,Float: Yb,Float: Xe,Float: Ye) ; // Dunno how to name it...
stock Float: atan2VehicleZ( Float: Xb,Float: Yb,Float: Xe,Float: Ye)
{
new Float: a = floatabs( 360.0 - atan2 ( Xe- Xb,Ye- Yb) ) ;
if ( 360 > a > 180 ) return a;
return a- 360.0 ;
}
//----------------------------------------------------------------------------//
Ly9BdXRvUGlsb3Qgc2NyaXB0IGJ5IEdhbWVyX1ogdjAuMgojaW5jbHVkZSA8YV9zYW1wPi8vU0E6TVAgVGVhbQojZGVmaW5lIEZJTFRFUlNDUklQVAojaW5jbHVkZSA8Um91dGVDb25uZWN0b3I+Ly9HUFMgUGx1Z2luCiNpbmNsdWRlIDx6Y21kPi8vQnkgWmVleAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwovLyNkZWZpbmUgVVNFX1RJTUVSUwojZGVmaW5lIFVTRV9TTU9PVEhfVFVSTlMgLy8gdGhhbmtzIHRvIHJpY2hhcmRjb3I5MSBmb3IgdGhlIFNldFZlaGljbGVBbmd1bGFyVmVsb2NpdHkgaGVscAovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwpuZXcgaWRbTUFYX1BMQVlFUlNdID0gey0xLC4uLn07Cm5ldyBDdXJyVGFyZ2V0W01BWF9QTEFZRVJTXSA9IHswLC4uLn07Cm5ldyBUaW1lcltNQVhfUExBWUVSU10gPSB7LTEsLi4ufTsKbmV3IEZsb2F0OnNwZFtNQVhfUExBWUVSU10gPSB7MC4zMCwuLi59OwojaWYgZGVmaW5lZCBVU0VfVElNRVJTCm5ldyBpbnRlcnZhbFtNQVhfUExBWUVSU10gPSB7MjUwLC4uLn07CiNlbmRpZgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwplbnVtIGxvY2F0aW9uCnsKICAgIG5hbWVbMTZdLAoJRmxvYXQ6WCwKCUZsb2F0OlksCglGbG9hdDpaCn0KCiNkZWZpbmUgUExBQ0VTICg2KQpuZXcgcGxhY2VzW1BMQUNFU11bbG9jYXRpb25dID0KewoJeyJMVi1jIiwyMTQwLjY2NzUsOTkzLjE4NjcsMTAuNTI0OH0sLy9MYXMgVmVudHVyYXMKCXsiU0YtYyIsLTIyNjEuMjAwOSw1NjQuMjg5NCwzNC43MjAwfSwvL1NhbiBGcmllcnJvCgl7IkxTLWMiLDI0OTUuMzc1NSwtMTY2OS40OTA2LDEzLjUxNjN9LC8vTG9zIFNhbnRvcwoJeyJMVi1hIiwxNjg2LjMxMDcsMTYwOS41NDg1LDEwLjgyMDN9LC8vTGFzIFZlbnR1cmFzIEFpcnBvcnQKCXsiU0YtYSIsLTE1MzguODYzNSwtNDIyLjkxNDIsNS44NTE2fSwvL1NhbiBGcmllcnJvIEFpcnBvcnQKCXsiTFMtYSIsMTk1My41MjA0LC0yMjkwLjExMzAsMTMuNTQ2OX0vL0xvcyBTYW50b3MgQWlycG9ydAp9OwovLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwpDTUQ6YXV0b3BpbG90KHBsYXllcmlkLHBhcmFtc1tdKQp7CglpZighSXNQbGF5ZXJJbkFueVZlaGljbGUocGxheWVyaWQpKQoJewoJCVNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgWU9VIE1VU1QgQkUgSU4gQSBWRUhJQ0xFIik7CgkgICAgcmV0dXJuIDE7Cgl9CglpZighc3RyY21wKHBhcmFtcywic3RvcCIsdHJ1ZSkpCgl7CgkJaWYoVGltZXJbcGxheWVyaWRdICE9ICgtMSkpCgkJewoJCSAgICAjaWYgZGVmaW5lZCBVU0VfVElNRVJTCgkJICAgIEtpbGxUaW1lcihUaW1lcltwbGF5ZXJpZF0pOwoJCSAgICAjZW5kaWYKCQkgICAgVGltZXJbcGxheWVyaWRdID0gLTE7CgkJICAgIERlbGV0ZUFycmF5KGlkW3BsYXllcmlkXSk7CgkJICAgIGlkW3BsYXllcmlkXSA9IC0xOwoJCSAgICBDdXJyVGFyZ2V0W3BsYXllcmlkXSA9IDA7CgkJICAgIFNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgRElTQUJMRUQiKTsKCQkgICAgcmV0dXJuIDE7CgkJfQoJCVNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgQ09VTEROJ1QgQkUgRElTQUJMRUQiKTsKCSAgICByZXR1cm4gMTsKCX0KCWlmKHBhcmFtc1swXSA9PSA0OCAmJiBwYXJhbXNbMV0gPT0gNDYpCgl7CgkgICAgaWYoaWRbcGxheWVyaWRdID09IC0xKQoJICAgIHsKCQkJbmV3IG91dFszMl07CgkJCWlmKCFpc051bWVyaWMocGFyYW1zWzJdKSkKCQkJewoJCQkgICAgU2VuZENsaWVudE1lc3NhZ2UocGxheWVyaWQsLTEsIkFVVE9QSUxPVCBTUEVFRCBNVVNUIEJFIEJFVFdFRU4gMC4wMSBhbmQgMC44MCIpOwoJCQkgICAgcmV0dXJuIDE7CgkJCX0KCQkJaWYoIWlzTnVtZXJpYyhwYXJhbXNbM10pKQoJCQkJcGFyYW1zWzNdID0gNDg7CgkJCWZvcm1hdChvdXQsMzIsIiVjJWMiLHBhcmFtc1syXSxwYXJhbXNbM10pOwoJCQluZXcgRmxvYXQ6dG1wc3BkID0gZmxvYXRkaXYoc3RydmFsKG91dCksMTAwLjAwKTsKCQkJaWYoMC4wMSA+IHRtcHNwZCA+IDAuODApCgkJCXsKCQkJICAgIFNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgU1BFRUQgTVVTVCBCRSBCRVRXRUVOIDAuMDEgYW5kIDAuODAiKTsKCQkJICAgIHJldHVybiAxOwoJCQl9CgkgICAgICAgIHNwZFtwbGF5ZXJpZF0gPSB0bXBzcGQ7CgkgICAgICAgIGZvcm1hdChvdXQsMzIsIkFVVE9QSUxPVCBTUEVFRCBTRVQgVE86ICUuM2YiLHNwZFtwbGF5ZXJpZF0pOwoJICAgICAgICBTZW5kQ2xpZW50TWVzc2FnZShwbGF5ZXJpZCwtMSxvdXQpOwoJCX0KCQllbHNlCgkJewoJCQlTZW5kQ2xpZW50TWVzc2FnZShwbGF5ZXJpZCwtMSwiQVVUT1BJTE9UIENBTk5PVCBDSEFOR0UgU1BFRUQgV0hJTEUgRFJJVklORyAoYnVnIHByZXZlbnRpb24pIik7CgkJfQogICAgICAgIHJldHVybiAxOwoJfQoJCiAgICBpZihpZFtwbGF5ZXJpZF0gPT0gLTEpCiAgICB7CiAgICAgICAgaWYgKHBhcmFtc1swXSA9PSAwIHx8IChwYXJhbXNbMF0gPT0gMSAmJiBwYXJhbXNbMV0gPT0gMCkpCiAgICAgICAgewogICAgICAgICAgICBTZW5kQ2xpZW50TWVzc2FnZShwbGF5ZXJpZCwtMSwiQVVUT1BJTE9UIEhBUyBOTyBUQVJHRVQiKTsKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgfQogICAgICAgIG5ldyBwbGFjZSA9IC0xOwogICAgICAgIGZvcihuZXcgaSA9IDA7IGkgPCBQTEFDRVM7ICsraSkKICAgICAgICB7CiAgICAgICAgICAgIGlmKCFzdHJjbXAocGxhY2VzW2ldW25hbWVdLHBhcmFtcyx0cnVlKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcGxhY2UgPSBpOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgaWYocGxhY2UgPT0gLTEpCiAgICAgICAgewogICAgICAgICAgICBTZW5kQ2xpZW50TWVzc2FnZShwbGF5ZXJpZCwtMSwiQVVUT1BJTE9UIERPRVNOJ1QgS05PVyBUSEFUIFBMQUNFIik7CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgIH0KICAgICAgICBuZXcgc3RhcnQgPSBOZWFyZXN0UGxheWVyTm9kZShwbGF5ZXJpZCwxNS4wKTsKICAgICAgICBpZihzdGFydCA9PSAtMSkKICAgICAgICB7CiAgICAgICAgICAgIFNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgTUFMRlVOQ1RJT04sIFBMRUFTRSBUUlkgQUdBSU4gT04gQU5PVEhFUiBQTEFDRSIpOwogICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICB9CgkJQ2FsY3VsYXRlUGF0aChzdGFydCxOZWFyZXN0Tm9kZUZyb21Qb2ludChwbGFjZXNbcGxhY2VdW1hdLHBsYWNlc1twbGFjZV1bWV0scGxhY2VzW3BsYWNlXVtaXSkscGxheWVyaWQpOwoJCVNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgSVMgQ0FMQ1VMQVRJTkcgVEhFIFJPVVRFIEZPUiBZT1UuLiIpOwoJCXJldHVybiAxOwoJfQogCVNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJBVVRPUElMT1QgQUxSRUFEWSBUVVJORUQgT04iKTsKICAgIHJldHVybiAxOwp9CgpDTUQ6YXAocGxheWVyaWQscGFyYW1zW10pCnsKICAgIHJldHVybiBjbWRfYXV0b3BpbG90KHBsYXllcmlkLHBhcmFtcyk7Cn0KCnN0b2NrIGlzTnVtZXJpYyhjb25zdCBzdHJpbmdbXSkKewogIG5ldyBsZW5ndGg9c3RybGVuKHN0cmluZyk7CiAgaWYgKGxlbmd0aD09MCkgcmV0dXJuIGZhbHNlOwogIGZvciAobmV3IGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspCgl7CgkgIGlmICgKCQkJKHN0cmluZ1tpXSA+ICc5JyB8fCBzdHJpbmdbaV0gPCAnMCcgJiYgc3RyaW5nW2ldIT0nLScgJiYgc3RyaW5nW2ldIT0nKycpIC8vIE5vdCBhIG51bWJlciwnKycgb3IgJy0nCgkJCSB8fCAoc3RyaW5nW2ldPT0nLScgJiYgaSE9MCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBICctJyBidXQgbm90IGF0IGZpcnN0LgoJCQkgfHwgKHN0cmluZ1tpXT09JysnICYmIGkhPTApICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQSAnKycgYnV0IG5vdCBhdCBmaXJzdC4KCQkgKSByZXR1cm4gZmFsc2U7Cgl9CiAgaWYgKGxlbmd0aD09MSAmJiAoc3RyaW5nWzBdPT0nLScgfHwgc3RyaW5nWzBdPT0nKycpKSByZXR1cm4gZmFsc2U7CiAgcmV0dXJuIHRydWU7Cn0KCiNpZiBkZWZpbmVkIFVTRV9USU1FUlMKQ01EOmludGVydmFsKHBsYXllcmlkLHBhcmFtc1tdKQp7CiAgICBpbnRlcnZhbFtwbGF5ZXJpZF0gPSBzdHJ2YWwocGFyYW1zKTsKICAgIGZvcm1hdChzdHJpbmcsMTI4LCJJbnRlcnZhbDogJWQiLGludGVydmFsKTsKICAgIFNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLHN0cmluZyk7CiAgICByZXR1cm4gMTsKfQojZW5kaWYKLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KcHVibGljIEdQU19XaGVuUm91dGVJc0NhbGN1bGF0ZWQocm91dGVpZCxub2RlX2lkX2FycmF5W10sYW1vdW50X29mX25vZGVzLGRpc3RhbmNlKQp7CglpZFtyb3V0ZWlkXSA9IFN0b3JlUm91dGVBcnJheShhbW91bnRfb2Zfbm9kZXMsbm9kZV9pZF9hcnJheSk7CiAgICAjaWYgZGVmaW5lZCBVU0VfVElNRVJTCglUaW1lcltyb3V0ZWlkXSA9IFNldFRpbWVyRXgoIkF1dG9QaWxvdCIsaW50ZXJ2YWxbcm91dGVpZF0sMSwiaSIscm91dGVpZCk7CgkjZWxzZQogICAgVGltZXJbcm91dGVpZF0gPSAxOwogICAgI2VuZGlmCiAgICBTZW5kQ2xpZW50TWVzc2FnZShyb3V0ZWlkLC0xLCIuLiBBVVRPUElMT1QgV0lMTCBEUklWRSBZT1UgTk9XIFRPIFlPVVIgREVTVElOQVRJT04iKTsKCXJldHVybiAxOwp9CgojaWYgZGVmaW5lZCBVU0VfVElNRVJTCgojZWxzZQpwdWJsaWMgT25QbGF5ZXJVcGRhdGUocGxheWVyaWQpCnsKCWlmKFRpbWVyW3BsYXllcmlkXSA9PSAxKQoJCUF1dG9QaWxvdChwbGF5ZXJpZCk7CglyZXR1cm4gMTsKfQojZW5kaWYKCnB1YmxpYyBPblBsYXllckNvbm5lY3QocGxheWVyaWQpCnsKICAgIFRpbWVyW3BsYXllcmlkXSA9IC0xOwogICAgaWRbcGxheWVyaWRdID0gLTE7CiAgICBDdXJyVGFyZ2V0W3BsYXllcmlkXSA9IDA7CiAgICAjaWYgZGVmaW5lZCBVU0VfVElNRVJTCiAgICBpbnRlcnZhbFtwbGF5ZXJpZF0gPSAyNTA7CiAgICAjZW5kaWYKCXJldHVybiAxOwp9CgpwdWJsaWMgT25QbGF5ZXJEaXNjb25uZWN0KHBsYXllcmlkLHJlYXNvbikKewoJaWYoVGltZXJbcGxheWVyaWRdICE9ICgtMSkpCgl7CgkgICAgI2lmIGRlZmluZWQgVVNFX1RJTUVSUwoJICAgIEtpbGxUaW1lcihUaW1lcltwbGF5ZXJpZF0pOwoJICAgICNlbmRpZgoJICAgIFRpbWVyW3BsYXllcmlkXSA9IC0xOwoJICAgIERlbGV0ZUFycmF5KGlkW3BsYXllcmlkXSk7CgkgICAgaWRbcGxheWVyaWRdID0gLTE7CgkgICAgQ3VyclRhcmdldFtwbGF5ZXJpZF0gPSAwOwoJfQoJcmV0dXJuIDE7Cn0KCmZvcndhcmQgQXV0b1BpbG90KHBsYXllcmlkKTsKcHVibGljIEF1dG9QaWxvdChwbGF5ZXJpZCkKewoJaWYoSXNQbGF5ZXJJbkFueVZlaGljbGUocGxheWVyaWQpKQoJewoJICAgIG5ldyBGbG9hdDpwb3NbMl1bM107CgkgICAgbmV3IHZlaGljbGVpZCA9IEdldFBsYXllclZlaGljbGVJRChwbGF5ZXJpZCk7CgkgICAgaWYoQ3VyclRhcmdldFtwbGF5ZXJpZF0gPT0gMCkKCSAgICB7CgkgICAgICAgIEN1cnJUYXJnZXRbcGxheWVyaWRdKys7CgkgICAgICAgIEdldE5vZGVQb3MoR2V0Um91dGVBdFBvcyhpZFtwbGF5ZXJpZF0sQ3VyclRhcmdldFtwbGF5ZXJpZF0pLHBvc1swXVswXSxwb3NbMF1bMV0scG9zWzBdWzJdKTsKCSAgICAgICAgU2V0VmVoaWNsZVBvcyh2ZWhpY2xlaWQscG9zWzBdWzBdLHBvc1swXVsxXSxwb3NbMF1bMl0rMi4wKTsKCSAgICAgICAgcmV0dXJuIDE7CgkgICAgfQoJICAgIG5ldyBhbW91bnQ7CgkJbmV3IG5vZGVpZCA9IEdldFJvdXRlQXRQb3MoaWRbcGxheWVyaWRdLEN1cnJUYXJnZXRbcGxheWVyaWRdLGFtb3VudCk7CgkJaWYoKEN1cnJUYXJnZXRbcGxheWVyaWRdKzEpID49IGFtb3VudCkKCQl7CgkJICAgICNpZiBkZWZpbmVkIFVTRV9USU1FUlMKCQkgICAgS2lsbFRpbWVyKFRpbWVyW3BsYXllcmlkXSk7CgkJICAgICNlbmRpZgoJCSAgICBUaW1lcltwbGF5ZXJpZF0gPSAtMTsKCQkgICAgRGVsZXRlQXJyYXkoaWRbcGxheWVyaWRdKTsKCQkgICAgaWRbcGxheWVyaWRdID0gLTE7CgkJICAgIEN1cnJUYXJnZXRbcGxheWVyaWRdID0gMDsKCQkgICAgU2V0VmVoaWNsZVZlbG9jaXR5KHZlaGljbGVpZCwwLjAsMC4wLDAuMCk7CgkJICAgIFNlbmRDbGllbnRNZXNzYWdlKHBsYXllcmlkLC0xLCJEZXN0aW5hdGlvbiByZWFjaGVkLCBoYXZlIGEgbmljZSBkYXkuIik7CgkJICAgIHJldHVybiAxOwoJCX0KICAgICAgICBHZXROb2RlUG9zKG5vZGVpZCxwb3NbMV1bMF0scG9zWzFdWzFdLHBvc1sxXVsyXSk7CiAgICAgICAgaWYoSXNQbGF5ZXJJblJhbmdlT2ZQb2ludChwbGF5ZXJpZCwxMC4wLHBvc1sxXVswXSxwb3NbMV1bMV0scG9zWzFdWzJdKSkKICAgICAgICB7CiAgICAgICAgICAgIEN1cnJUYXJnZXRbcGxheWVyaWRdKys7CiAgICAgICAgICAgIHJldHVybiAxOwogICAgICAgIH0KICAgICAgIAlQdWxsVmVoaWNsZUludG9EaXJlY3Rpb24odmVoaWNsZWlkLHBvc1sxXVswXSxwb3NbMV1bMV0scG9zWzFdWzJdLHNwZFtwbGF5ZXJpZF0pOwoJfQoJZWxzZQoJewoJICAgICNpZiBkZWZpbmVkIFVTRV9USU1FUlMKCSAgICBLaWxsVGltZXIoVGltZXJbcGxheWVyaWRdKTsKCSAgICAjZW5kaWYKCSAgICBUaW1lcltwbGF5ZXJpZF0gPSAtMTsKCSAgICBEZWxldGVBcnJheShpZFtwbGF5ZXJpZF0pOwoJICAgIGlkW3BsYXllcmlkXSA9IC0xOwoJICAgIEN1cnJUYXJnZXRbcGxheWVyaWRdID0gMDsKCX0KCXJldHVybiAxOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS1BVVRPLVBJTE9ULUNPUkUtRlVOQ1RJT05TLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8vCiNkZWZpbmUgREVQUkVDQVRFX1oKc3RvY2sgUHVsbFZlaGljbGVJbnRvRGlyZWN0aW9uKHZlaGljbGVpZCwgRmxvYXQ6eCwgRmxvYXQ6eSwgRmxvYXQ6eiwgRmxvYXQ6c3BlZWQpLy9UaGFua3MgdG8gTWlndWVsIGZvciBzdXBwbHlpbmcgbWUgd2l0aCB0aGlzIGZ1bmN0aW9uLCBJIGhhdmUgZWRpdGVkIGl0IGEgYml0CnsKCW5ldwogICAgICAgIEZsb2F0OmRpc3RhbmNlLAogICAgICAgIEZsb2F0OnZlaGljbGVfcG9zWzNdOwoKICAgIEdldFZlaGljbGVQb3ModmVoaWNsZWlkLCB2ZWhpY2xlX3Bvc1swXSwgdmVoaWNsZV9wb3NbMV0sIHZlaGljbGVfcG9zWzJdKTsKCSNpZiBkZWZpbmVkIFVTRV9TTU9PVEhfVFVSTlMKCW5ldyBGbG9hdDogb3ogPSBhdGFuMlZlaGljbGVaKHZlaGljbGVfcG9zWzBdLCB2ZWhpY2xlX3Bvc1sxXSwgeCwgeSk7CgluZXcgRmxvYXQ6IHZ6OwoJR2V0VmVoaWNsZVpBbmdsZSh2ZWhpY2xlaWQsIHZ6KTsKCWlmKG96IDwgdnotMTgwKSBveiA9IG96KzM2MDsKCWlmKHZ6IDwgb3otMTgwKSB2eiA9IHZ6KzM2MDsKCW5ldyBGbG9hdDogY3ogPSBmbG9hdGFicyh2eiAtIG96KTsKCSNlbHNlCglTZXRWZWhpY2xlWkFuZ2xlKHZlaGljbGVpZCwgYXRhbjJWZWhpY2xlWih2ZWhpY2xlX3Bvc1swXSwgdmVoaWNsZV9wb3NbMV0sIHgsIHkpKTsKCSNlbmRpZgogICAgeCAtPSB2ZWhpY2xlX3Bvc1swXTsKICAgIHkgLT0gdmVoaWNsZV9wb3NbMV07CiAgICB6IC09IHZlaGljbGVfcG9zWzJdOwogICAgI2lmIGRlZmluZWQgREVQUkVDQVRFX1oKICAgIGRpc3RhbmNlID0gZmxvYXRzcXJvb3QoKHggKiB4KSArICh5ICogeSkpOwogICAgeCA9IChzcGVlZCAqIHgpIC8gZGlzdGFuY2U7CiAgICB5ID0gKHNwZWVkICogeSkgLyBkaXN0YW5jZTsKICAgIEdldFZlaGljbGVWZWxvY2l0eSh2ZWhpY2xlaWQsIHZlaGljbGVfcG9zWzBdLCB2ZWhpY2xlX3Bvc1swXSwgeik7CiAgICAjZWxzZQogICAgeis9MC4xMTsKICAgIGRpc3RhbmNlID0gZmxvYXRzcXJvb3QoKHggKiB4KSArICh5ICogeSkgKyAoeiAqIHopKTsKICAgIHggPSAoc3BlZWQgKiB4KSAvIGRpc3RhbmNlOwogICAgeSA9IChzcGVlZCAqIHkpIC8gZGlzdGFuY2U7CiAgICB6ID0gKHNwZWVkICogeikgLyBkaXN0YW5jZTsKICAgICNlbmRpZgoJI2lmIGRlZmluZWQgVVNFX1NNT09USF9UVVJOUwoJaWYoY3ogPiAwKQogCXsKCQluZXcgRmxvYXQ6IGZ6ID0gY3oqMC4wMDE1OwoJCWlmKHZ6IDwgb3opIFNldFZlaGljbGVBbmd1bGFyVmVsb2NpdHkodmVoaWNsZWlkLCAwLjAsIDAuMCwgZnopOwoJCWlmKHZ6ID4gb3opIFNldFZlaGljbGVBbmd1bGFyVmVsb2NpdHkodmVoaWNsZWlkLCAwLjAsIDAuMCwgLWZ6KTsKCX0KCSNlbmRpZgogICAgU2V0VmVoaWNsZVZlbG9jaXR5KHZlaGljbGVpZCwgeCwgeSwgeik7Cn0KCmZvcndhcmQgRmxvYXQ6YXRhbjJWZWhpY2xlWihGbG9hdDpYYixGbG9hdDpZYixGbG9hdDpYZSxGbG9hdDpZZSk7Ly8gRHVubm8gaG93IHRvIG5hbWUgaXQuLi4Kc3RvY2sgRmxvYXQ6YXRhbjJWZWhpY2xlWihGbG9hdDpYYixGbG9hdDpZYixGbG9hdDpYZSxGbG9hdDpZZSkKewoJbmV3IEZsb2F0OmEgPSBmbG9hdGFicygzNjAuMCAtIGF0YW4yKCBYZS1YYixZZS1ZYikpOwoJaWYoMzYwID4gYSA+IDE4MClyZXR1cm4gYTsKCXJldHVybiBhLTM2MC4wOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8v