--[[------------------------------------------------------------------------
ActionMenu
Created by WolfKnight
Additional help from lowheartrate, TheStonedTurtle, and Briglair.
Modified by Christopher for VisionaryRP
------------------------------------------------------------------------]]--
-- Define the variable used to open/close the menu
local menuEnabled = false
local togShot = false
local togAr = false
local togWin = false
local vd0 = false
local vd1 = false
local vd2 = false
local vd3 = false
local vd4 = false
local vd5 = false
local vd6 = false
local vd7 = false
local SpawnedSpikes = {}
local SpikesSpawned = false
local SpikeConfig = {}
local SpikeConfig = setmetatable(SpikeConfig, {})
SpikeConfig.MaxSpikes = 3
SpikeConfig.PedRestriction = true
SpikeConfig.PedsList = {
"s_m_y_cop_01",
"s_f_y_cop_01",
"s_m_y_hwaycop_01",
"s_m_y_sheriff_01",
"s_f_y_sheriff_01",
"s_m_y_swat_01",
"s_m_y_ranger_01",
"s_f_y_ranger_01",
"s_m_m_ciasec_01",
"u_m_m_doa_01",
"s_m_m_fibsec_01"
}
local gear = {
{"WEAPON_COMBATPISTOL"},
{"WEAPON_NIGHTSTICK"},
{"WEAPON_STUNGUN"},
{"WEAPON_FLASHLIGHT"},
}
--[[------------------------------------------------------------------------
ActionMenu Toggle
Calling this function will open or close the ActionMenu.
------------------------------------------------------------------------]]--
function ToggleActionMenu()
-- Make the menuEnabled variable not itself
-- e.g. not true = false, not false = true
menuEnabled = not menuEnabled
if ( menuEnabled ) then
-- Focuses on the NUI, the second parameter toggles the
-- onscreen mouse cursor.
SetNuiFocus( true, true )
-- Sends a message to the JavaScript side, telling it to
-- open the menu.
SendNUIMessage({
showmenu = true
})
else
-- Bring the focus back to the game
SetNuiFocus( false )
-- Sends a message to the JavaScript side, telling it to
-- close the menu.
SendNUIMessage({
hidemenu = true
})
end
end
--[[------------------------------------------------------------------------
ActionMenu HTML Callbacks
This will be called every single time the JavaScript side uses the
sendData function. The name of the data-action is passed as the parameter
variable data.
------------------------------------------------------------------------]]--
RegisterNUICallback( "ButtonClick", function( data, cb )
if ( data == "shotgun" ) then
if IsPedInAnyVehicle(GetPlayerPed(-1)) then
if ( togShot ) then
Citizen.CreateThread(function()
RemoveAllPedWeapons(GetPlayerPed(-1),true)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_STUNGUN"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_FLASHLIGHT"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_NIGHTSTICK"), 1000, false)
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), GetHashKey("COMPONENT_AT_PI_FLSH"))
SetCurrentPedWeapon(GetPlayerPed(-1), "WEAPON_UNARMED", true)
chatPrint( "You put your Shotgun away" )
dontWant()
togShot = false
end)
else
Citizen.CreateThread(function()
RemoveAllPedWeapons(GetPlayerPed(-1),true)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_STUNGUN"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_FLASHLIGHT"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_NIGHTSTICK"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_PUMPSHOTGUN"), 1000, false)
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), GetHashKey("COMPONENT_AT_PI_FLSH"))
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_PUMPSHOTGUN"), GetHashKey("COMPONENT_AT_AR_FLSH"))
SetCurrentPedWeapon(GetPlayerPed(-1), "WEAPON_PUMPSHOTGUN", true)
chatPrint( "You unlock your Shotgun" )
want("0x1D073A89")
togShot = true
end)
end
else
chatPrint( "I can't pull a Shotgun out of thin air..." )
end
elseif ( data == "ar15" ) then
if IsPedInAnyVehicle(GetPlayerPed(-1)) then
if ( togAr ) then
Citizen.CreateThread(function()
RemoveAllPedWeapons(GetPlayerPed(-1),true)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_STUNGUN"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_FLASHLIGHT"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_NIGHTSTICK"), 1000, false)
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), GetHashKey("COMPONENT_AT_PI_FLSH"))
SetCurrentPedWeapon(GetPlayerPed(-1), "WEAPON_UNARMED", true)
chatPrint( "You put your AR-15 away" )
dontWant()
togAr = false
end)
else
Citizen.CreateThread(function()
RemoveAllPedWeapons(GetPlayerPed(-1),true)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_STUNGUN"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_FLASHLIGHT"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_NIGHTSTICK"), 1000, false)
GiveWeaponToPed(GetPlayerPed(-1), GetHashKey("WEAPON_CARBINERIFLE"), 1000, false)
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), GetHashKey("COMPONENT_AT_PI_FLSH"))
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_CARBINERIFLE"), GetHashKey("COMPONENT_AT_AR_AFGRIP"))
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_CARBINERIFLE"), GetHashKey("COMPONENT_AT_AR_FLSH"))
SetCurrentPedWeapon(GetPlayerPed(-1), "WEAPON_CARBINERIFLE", true)
chatPrint( "You unlock your AR-15" )
want("0x83BF0278")
togAr = true
end)
end
else
chatPrint( "I can't pull an AR15 out of thin air..." )
end
elseif ( data == "gear" ) then
if IsPedInAnyVehicle(GetPlayerPed(-1)) then
RequestModel("s_m_y_hwaycop_01")
while not HasModelLoaded("s_m_y_hwaycop_01") do
Citizen.Wait(0)
end
SetPlayerModel(PlayerId(), GetHashKey("s_m_y_hwaycop_01"))
for k, w in pairs(gear) do
GiveWeaponToPed(GetPlayerPed(-1), w[1], 1000, false, false)
end
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_COMBATPISTOL"), GetHashKey("COMPONENT_AT_PI_FLSH"))
GiveWeaponComponentToPed(GetPlayerPed(-1), GetHashKey("WEAPON_PUMPSHOTGUN"), GetHashKey("COMPONENT_AT_AR_FLSH"))
else
chatPrint( "I can't pull my Gear out of thin air..." )
end
elseif ( data == "d1" ) then
ss(1)
elseif ( data == "d2" ) then
ss(2)
elseif ( data == "d3" ) then
ss(3)
elseif ( data == "ds" ) then
ds()
elseif ( data == "togRadar" ) then
if IsPedInAnyVehicle(GetPlayerPed(-1)) then
togRadar()
else
chatPrint( "I can't pull a Radar out of thin air..." )
end
elseif ( data == "cuff" ) then
Citizen.CreateThread( function()
AddTextEntry('FMMC_KEY_TIP1', "Enter the Civilian's ID")
DisplayOnscreenKeyboard( false, "FMMC_KEY_TIP1", "", "", "", "", "", 4 )
while true do
if ( UpdateOnscreenKeyboard() == 1 ) then
local cuffStr = GetOnscreenKeyboardResult()
if ( string.len( cuffStr ) > 0 ) then
local cuff = tonumber( cuffStr )
if ( cuff < 999 and cuff >= 1 ) then
local tPID = cuffStr
TriggerEvent("Handcuff", tPID)
end
break
else
DisplayOnscreenKeyboard( false, "", "", "", "", "", "", 4 )
end
elseif ( UpdateOnscreenKeyboard() == 2 ) then
break
end
Citizen.Wait( 0 )
end
end )
elseif ( data == "vd0" ) then
if ( vd0 ) then
closeDoor(0)
vd0 = false
else
openDoor(0)
vd0 = true
end
elseif ( data == "vd1" ) then
if ( vd1 ) then
closeDoor(1)
vd1 = false
else
openDoor(1)
vd1 = true
end
elseif ( data == "vd2" ) then
if ( vd2 ) then
closeDoor(2)
vd2 = false
else
openDoor(2)
vd2 = true
end
elseif ( data == "vd3" ) then
if ( vd3 ) then
closeDoor(3)
vd3 = false
else
openDoor(3)
vd3 = true
end
elseif ( data == "vd4" ) then
if ( vd4 ) then
closeDoor(4)
vd5 = false
else
openDoor(4)
vd4 = true
end
elseif ( data == "vd5" ) then
if ( vd5 ) then
closeDoor(5)
vd5 = false
else
openDoor(5)
vd5 = true
end
elseif ( data == "vd6" ) then
if ( vd6 ) then
closeDoor(6)
vd6 = false
else
openDoor(6)
vd6 = true
end
elseif ( data == "vd7" ) then
if ( vd7) then
closeDoor(7)
vd7 = false
else
openDoor(7)
vd7 = true
end
elseif ( data == "vdc" ) then
closeAllDoors()
elseif ( data == "engine" ) then
toggleEngine()
elseif ( data == "windows" ) then
toggleWindows()
elseif ( data == "exit" ) then
-- We toggle the ActionMenu and return here, otherwise the function
-- call below would be executed too, which would just open the menu again
ToggleActionMenu()
return
end
-- This will only be called if any button other than the exit button is pressed
ToggleActionMenu()
end )
--[[------------------------------------------------------------------------
ActionMenu Control and Input Blocking
This is the main while loop that opens the ActionMenu on keypress. It
uses the input blocking found in the ES Banking resource, credits to
the authors.
------------------------------------------------------------------------]]--
Citizen.CreateThread( function()
-- This is just in case the resources restarted whilst the NUI is focused.
SetNuiFocus( false )
while true do
-- Control ID 20 is the 'Z' key by default
-- Use https://w...content-available-to-author-only...m.net/wiki/Controls to find a different key
-- Now set to M
if ( IsControlJustPressed( 1, 244 ) ) then
ToggleActionMenu()
end
if ( menuEnabled ) then
local ped = GetPlayerPed( -1 )
DisableControlAction( 0, 1, true ) -- LookLeftRight
DisableControlAction( 0, 2, true ) -- LookUpDown
DisableControlAction( 0, 24, true ) -- Attack
DisablePlayerFiring( ped, true ) -- Disable weapon firing
DisableControlAction( 0, 142, true ) -- MeleeAttackAlternate
DisableControlAction( 0, 106, true ) -- VehicleMouseControlOverride
end
Citizen.Wait( 0 )
end
end )
function chatPrint( msg )
TriggerEvent( 'chatMessage', "VisionaryRP", { 255, 255, 255 }, msg )
end
function ss( num )
TriggerEvent( 'Spikestrips:SpawnSpikes', {isRestricted = SpikeConfig.PedRestriction, pedList = SpikeConfig.PedsList,}, num )
end
function ds()
TriggerEvent( 'Spikestrips:RemoveSpikes')
end
function togRadar()
TriggerEvent( 'wk:radarRC')
end
function want(wea)
TriggerEvent( 'PoliceVehicleWeaponDeleter:gettingAGun', wea)
end
function dontWant(wea)
TriggerEvent( 'PoliceVehicleWeaponDeleter:notGettingAGun')
end
function openDoor(vd)
local Veh = GetVehiclePedIsUsing(GetPlayerPed(-1))
SetVehicleDoorOpen(Veh, vd, false, false)
end
function closeDoor(vd)
local Veh = GetVehiclePedIsUsing(GetPlayerPed(-1))
SetVehicleDoorShut(Veh, vd, false)
end
function closeAllDoors()
local Veh = GetVehiclePedIsUsing(GetPlayerPed(-1))
SetVehicleDoorShut(Veh, 0, false)
SetVehicleDoorShut(Veh, 1, false)
SetVehicleDoorShut(Veh, 2, false)
SetVehicleDoorShut(Veh, 3, false)
SetVehicleDoorShut(Veh, 4, false)
SetVehicleDoorShut(Veh, 5, false)
SetVehicleDoorShut(Veh, 6, false)
SetVehicleDoorShut(Veh, 7, false)
end
function toggleEngine()
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)
if vehicle ~= nil and vehicle ~= 0 and GetPedInVehicleSeat(vehicle, 0) then
SetVehicleEngineOn(vehicle, (not GetIsVehicleEngineRunning(vehicle)), false, true)
end
end
function toggleWindows()
if ( togWin ) then
RoleUpWindow(playerCar, 0)
RoleUpWindow(playerCar, 1)
RoleUpWindow(playerCar, 2)
RoleUpWindow(playerCar, 3)
togWin false
else
local playerCar = GetVehiclePedIsIn(playerPed, false)
RollDownWindows(playerCar)
togWin true
end
end
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
--[[ Looped Thread ]]--
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if IsPedInAnyVehicle(GetPlayerPed(PlayerId()), false) then
local vehicle = GetVehiclePedIsIn(GetPlayerPed(PlayerId()), false)
local vehiclePos = GetEntityCoords(vehicle, false)
local spikes = GetClosestObjectOfType(vehiclePos.x, vehiclePos.y, vehiclePos.z, 75.0, GetHashKey("P_ld_stinger_s"), false, 1, 1)
local spikesCoords = GetEntityCoords(spikes, false)
local distance = Vdist(vehiclePos.x, vehiclePos.y, vehiclePos.z, spikesCoords.x, spikesCoords.y, spikesCoords.z)
if distance <= 75.0 then
CheckDistanceToStrips()
end
end
end
end)
RegisterCommand("spawn", function(source, args, string)
SpawnSpikes()
end, false)
RegisterNetEvent("Spikestrips:SpawnSpikes")
AddEventHandler("Spikestrips:SpawnSpikes", function(config, amount)
if config.isRestricted then
if CheckPedRestriction(GetPlayerPed(PlayerId()), config.pedList) then
for a = 1, amount do
local plyCoords = GetOffsetFromEntityInWorldCoords(GetPlayerPed(PlayerId()), 0.0, 3.0 * a + 0.5, 0.0)
local plyHead = GetEntityHeading(GetPlayerPed(PlayerId()))
local spike = CreateObject(GetHashKey("P_ld_stinger_s"), plyCoords.x, plyCoords.y, plyCoords.z, true, 1, true)
local spikeHeight = GetEntityHeightAboveGround(spike)
SetEntityCoords(spike, plyCoords.x, plyCoords.y, plyCoords.z - spikeHeight + 0.05, 0.0, 0.0, 0.0, 0.0)
SetEntityHeading(spike, plyHead)
SetEntityAsMissionEntity(spike, 1, 1)
table.insert(SpawnedSpikes, spike)
SpikesSpawned = true
end
else
chatPrint( "Where the hell am I meant to get Spike Strips from?!" )
end
else
for b = 1, amount do
local plyCoords = GetOffsetFromEntityInWorldCoords(GetPlayerPed(PlayerId()), 0.0, 3.0 * b + 0.5, 0.0)
local plyHead = GetEntityHeading(GetPlayerPed(PlayerId()))
local spike = CreateObject(GetHashKey("P_ld_stinger_s"), plyCoords.x, plyCoords.y, plyCoords.z, true, 1, true)
local spikeHeight = GetEntityHeightAboveGround(spike)
SetEntityCoords(spike, plyCoords.x, plyCoords.y, plyCoords.z - spikeHeight + 0.05, 0.0, 0.0, 0.0, 0.0)
SetEntityHeading(spike, plyHead)
SetEntityAsMissionEntity(spike, 1, 1)
SetEntityCollision(spike, false, false)
table.insert(SpawnedSpikes, spike)
SpikesSpawned = true
end
end
end)
RegisterNetEvent("Spikestrips:RemoveSpikes")
AddEventHandler("Spikestrips:RemoveSpikes", function()
if SpikesSpawned then
for i = 1, #SpawnedSpikes do
DeleteEntity(SpawnedSpikes[i])
SpawnedSpikes[i] = nil
SpikesSpawned = false
end
end
end)
function CheckDistanceToStrips()
local vehicle = GetVehiclePedIsIn(GetPlayerPed(PlayerId()), false)
FrontLeftTire(vehicle)
FrontRightTire(vehicle)
BackLeftTire(vehicle)
BackRightTire(vehicle)
end
function FrontLeftTire(vehicle)
local tirePosition = GetWorldPositionOfEntityBone(vehicle, GetEntityBoneIndexByName(vehicle, "wheel_lf"))
local spikestrip = GetClosestObjectOfType(tirePosition.x, tirePosition.y, tirePosition.z, 15.0, GetHashKey("P_ld_stinger_s"), false, 1, 1)
local spikeCoords = GetEntityCoords(spikestrip, false)
local distance = Vdist(tirePosition.x, tirePosition.y, tirePosition.z, spikeCoords.x, spikeCoords.y, spikeCoords.z)
if distance < 1.8 then
if not IsVehicleTyreBurst(vehicle, 0, false) and not IsVehicleTyreBurst(vehicle, 0, true) then
SetVehicleTyreBurst(vehicle, 0, false, 1000.0)
end
end
end
function FrontRightTire(vehicle)
local tirePosition = GetWorldPositionOfEntityBone(vehicle, GetEntityBoneIndexByName(vehicle, "wheel_rf"))
local spikestrip = GetClosestObjectOfType(tirePosition.x, tirePosition.y, tirePosition.z, 15.0, GetHashKey("P_ld_stinger_s"), false, 1, 1)
local spikeCoords = GetEntityCoords(spikestrip, false)
local distance = Vdist(tirePosition.x, tirePosition.y, tirePosition.z, spikeCoords.x, spikeCoords.y, spikeCoords.z)
if distance < 1.8 then
if not IsVehicleTyreBurst(vehicle, 1, false) and not IsVehicleTyreBurst(vehicle, 1, true) then
SetVehicleTyreBurst(vehicle, 1, false, 1000.0)
end
end
end
function BackLeftTire(vehicle)
local tirePosition = GetWorldPositionOfEntityBone(vehicle, GetEntityBoneIndexByName(vehicle, "wheel_lr"))
local spikestrip = GetClosestObjectOfType(tirePosition.x, tirePosition.y, tirePosition.z, 15.0, GetHashKey("P_ld_stinger_s"), false, 1, 1)
local spikeCoords = GetEntityCoords(spikestrip, false)
local distance = Vdist(tirePosition.x, tirePosition.y, tirePosition.z, spikeCoords.x, spikeCoords.y, spikeCoords.z)
if distance < 1.8 then
if not IsVehicleTyreBurst(vehicle, 4, false) and not IsVehicleTyreBurst(vehicle, 4, true) then
SetVehicleTyreBurst(vehicle, 4, false, 1000.0)
SetVehicleTyreBurst(vehicle , 2, false, 1000.0)
end
end
end
function BackRightTire(vehicle)
local tirePosition = GetWorldPositionOfEntityBone(vehicle, GetEntityBoneIndexByName(vehicle, "wheel_rr"))
local spikestrip = GetClosestObjectOfType(tirePosition.x, tirePosition.y, tirePosition.z, 15.0, GetHashKey("P_ld_stinger_s"), false, 1, 1)
local spikeCoords = GetEntityCoords(spikestrip, false)
local distance = Vdist(tirePosition.x, tirePosition.y, tirePosition.z, spikeCoords.x, spikeCoords.y, spikeCoords.z)
if distance < 1.8 then
if not IsVehicleTyreBurst(vehicle, 5, false) and not IsVehicleTyreBurst(vehicle, 5, true) then
SetVehicleTyreBurst(vehicle, 5, false, 1000.0)
SetVehicleTyreBurst(vehicle , 3, false, 1000.0)
end
end
end
function CheckPedRestriction(ped, PedList)
for i = 1, #PedList do
print(tostring(GetHashKey(PedList[i])))
if GetHashKey(PedList[i]) == GetEntityModel(ped) then
return true
end
end
return false
end
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if SpikesSpawned then
for i = 1, #SpawnedSpikes do
FreezeEntityPosition(SpawnedSpikes[i], true)
end
end
end
end)
LS1bWy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogCglBY3Rpb25NZW51IAoJQ3JlYXRlZCBieSBXb2xmS25pZ2h0CglBZGRpdGlvbmFsIGhlbHAgZnJvbSBsb3doZWFydHJhdGUsIFRoZVN0b25lZFR1cnRsZSwgYW5kIEJyaWdsYWlyLgoJCglNb2RpZmllZCBieSBDaHJpc3RvcGhlciBmb3IgVmlzaW9uYXJ5UlAKIAotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1dXS0tCiAKLS0gRGVmaW5lIHRoZSB2YXJpYWJsZSB1c2VkIHRvIG9wZW4vY2xvc2UgdGhlIG1lbnUgCmxvY2FsIG1lbnVFbmFibGVkID0gZmFsc2UgCmxvY2FsIHRvZ1Nob3QgPSBmYWxzZQpsb2NhbCB0b2dBciA9IGZhbHNlCmxvY2FsIHRvZ1dpbiA9IGZhbHNlCgpsb2NhbCB2ZDAgPSBmYWxzZQpsb2NhbCB2ZDEgPSBmYWxzZQpsb2NhbCB2ZDIgPSBmYWxzZQpsb2NhbCB2ZDMgPSBmYWxzZQpsb2NhbCB2ZDQgPSBmYWxzZQpsb2NhbCB2ZDUgPSBmYWxzZQpsb2NhbCB2ZDYgPSBmYWxzZQpsb2NhbCB2ZDcgPSBmYWxzZQoKIApsb2NhbCBTcGF3bmVkU3Bpa2VzID0ge30KbG9jYWwgU3Bpa2VzU3Bhd25lZCA9IGZhbHNlCiAKbG9jYWwgU3Bpa2VDb25maWcgPSB7fQpsb2NhbCBTcGlrZUNvbmZpZyA9IHNldG1ldGF0YWJsZShTcGlrZUNvbmZpZywge30pCiAKU3Bpa2VDb25maWcuTWF4U3Bpa2VzID0gMwogClNwaWtlQ29uZmlnLlBlZFJlc3RyaWN0aW9uID0gdHJ1ZQpTcGlrZUNvbmZpZy5QZWRzTGlzdCA9IHsKCSJzX21feV9jb3BfMDEiLAoJInNfZl95X2NvcF8wMSIsCgkic19tX3lfaHdheWNvcF8wMSIsCgkic19tX3lfc2hlcmlmZl8wMSIsCgkic19mX3lfc2hlcmlmZl8wMSIsCgkic19tX3lfc3dhdF8wMSIsCgkic19tX3lfcmFuZ2VyXzAxIiwKCSJzX2ZfeV9yYW5nZXJfMDEiLAoJInNfbV9tX2NpYXNlY18wMSIsCiAgICAidV9tX21fZG9hXzAxIiwKCSJzX21fbV9maWJzZWNfMDEiCn0KIAogCmxvY2FsIGdlYXIgPSB7CiAgICB7IldFQVBPTl9DT01CQVRQSVNUT0wifSwKICAgIHsiV0VBUE9OX05JR0hUU1RJQ0sifSwKICAgIHsiV0VBUE9OX1NUVU5HVU4ifSwKICAgIHsiV0VBUE9OX0ZMQVNITElHSFQifSwKfQogCi0tW1stLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCUFjdGlvbk1lbnUgVG9nZ2xlCglDYWxsaW5nIHRoaXMgZnVuY3Rpb24gd2lsbCBvcGVuIG9yIGNsb3NlIHRoZSBBY3Rpb25NZW51LiAKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXV0tLQpmdW5jdGlvbiBUb2dnbGVBY3Rpb25NZW51KCkKCS0tIE1ha2UgdGhlIG1lbnVFbmFibGVkIHZhcmlhYmxlIG5vdCBpdHNlbGYgCgktLSBlLmcuIG5vdCB0cnVlID0gZmFsc2UsIG5vdCBmYWxzZSA9IHRydWUgCgltZW51RW5hYmxlZCA9IG5vdCBtZW51RW5hYmxlZAogCglpZiAoIG1lbnVFbmFibGVkICkgdGhlbiAKCQktLSBGb2N1c2VzIG9uIHRoZSBOVUksIHRoZSBzZWNvbmQgcGFyYW1ldGVyIHRvZ2dsZXMgdGhlIAoJCS0tIG9uc2NyZWVuIG1vdXNlIGN1cnNvci4gCgkJU2V0TnVpRm9jdXMoIHRydWUsIHRydWUgKQogCgkJLS0gU2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBKYXZhU2NyaXB0IHNpZGUsIHRlbGxpbmcgaXQgdG8gCgkJLS0gb3BlbiB0aGUgbWVudS4gCgkJU2VuZE5VSU1lc3NhZ2UoewoJCQlzaG93bWVudSA9IHRydWUgCgkJfSkKCWVsc2UgCgkJLS0gQnJpbmcgdGhlIGZvY3VzIGJhY2sgdG8gdGhlIGdhbWUKCQlTZXROdWlGb2N1cyggZmFsc2UgKQogCgkJLS0gU2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBKYXZhU2NyaXB0IHNpZGUsIHRlbGxpbmcgaXQgdG8KCQktLSBjbG9zZSB0aGUgbWVudS4KCQlTZW5kTlVJTWVzc2FnZSh7CgkJCWhpZGVtZW51ID0gdHJ1ZSAKCQl9KQoJZW5kIAplbmQgCiAKLS1bWy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoJQWN0aW9uTWVudSBIVE1MIENhbGxiYWNrcwoJVGhpcyB3aWxsIGJlIGNhbGxlZCBldmVyeSBzaW5nbGUgdGltZSB0aGUgSmF2YVNjcmlwdCBzaWRlIHVzZXMgdGhlCglzZW5kRGF0YSBmdW5jdGlvbi4gVGhlIG5hbWUgb2YgdGhlIGRhdGEtYWN0aW9uIGlzIHBhc3NlZCBhcyB0aGUgcGFyYW1ldGVyCgl2YXJpYWJsZSBkYXRhLiAKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXV0tLQpSZWdpc3Rlck5VSUNhbGxiYWNrKCAiQnV0dG9uQ2xpY2siLCBmdW5jdGlvbiggZGF0YSwgY2IgKSAKCWlmICggZGF0YSA9PSAic2hvdGd1biIgKSB0aGVuCgkJaWYgSXNQZWRJbkFueVZlaGljbGUoR2V0UGxheWVyUGVkKC0xKSkgdGhlbgoJCQlpZiAoIHRvZ1Nob3QgKSB0aGVuCgkJCQlDaXRpemVuLkNyZWF0ZVRocmVhZChmdW5jdGlvbigpCgkJCQkJUmVtb3ZlQWxsUGVkV2VhcG9ucyhHZXRQbGF5ZXJQZWQoLTEpLHRydWUpCgkJCQkJR2l2ZVdlYXBvblRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9DT01CQVRQSVNUT0wiKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvblRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9TVFVOR1VOIiksIDEwMDAsIGZhbHNlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fRkxBU0hMSUdIVCIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX05JR0hUU1RJQ0siKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvbkNvbXBvbmVudFRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9DT01CQVRQSVNUT0wiKSwgR2V0SGFzaEtleSgiQ09NUE9ORU5UX0FUX1BJX0ZMU0giKSkKCQkJCQlTZXRDdXJyZW50UGVkV2VhcG9uKEdldFBsYXllclBlZCgtMSksICJXRUFQT05fVU5BUk1FRCIsIHRydWUpCgkJCQkJY2hhdFByaW50KCAiWW91IHB1dCB5b3VyIFNob3RndW4gYXdheSIgKQoJCQkJCWRvbnRXYW50KCkKCQkJCQl0b2dTaG90ID0gZmFsc2UKCQkJCWVuZCkKCQkJZWxzZQoJCQkJQ2l0aXplbi5DcmVhdGVUaHJlYWQoZnVuY3Rpb24oKQoJCQkJCVJlbW92ZUFsbFBlZFdlYXBvbnMoR2V0UGxheWVyUGVkKC0xKSx0cnVlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fQ09NQkFUUElTVE9MIiksIDEwMDAsIGZhbHNlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fU1RVTkdVTiIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0ZMQVNITElHSFQiKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvblRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9OSUdIVFNUSUNLIiksIDEwMDAsIGZhbHNlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fUFVNUFNIT1RHVU4iKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvbkNvbXBvbmVudFRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9DT01CQVRQSVNUT0wiKSwgR2V0SGFzaEtleSgiQ09NUE9ORU5UX0FUX1BJX0ZMU0giKSkKCQkJCQlHaXZlV2VhcG9uQ29tcG9uZW50VG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX1BVTVBTSE9UR1VOIiksIEdldEhhc2hLZXkoIkNPTVBPTkVOVF9BVF9BUl9GTFNIIikpCgkJCQkJU2V0Q3VycmVudFBlZFdlYXBvbihHZXRQbGF5ZXJQZWQoLTEpLCAiV0VBUE9OX1BVTVBTSE9UR1VOIiwgdHJ1ZSkKCQkJCQljaGF0UHJpbnQoICJZb3UgdW5sb2NrIHlvdXIgU2hvdGd1biIgKQoJCQkJCXdhbnQoIjB4MUQwNzNBODkiKQoJCQkJCXRvZ1Nob3QgPSB0cnVlCgkJCQllbmQpCgkJCWVuZAoJCWVsc2UKCQkJY2hhdFByaW50KCAiSSBjYW4ndCBwdWxsIGEgU2hvdGd1biBvdXQgb2YgdGhpbiBhaXIuLi4iICkKCQllbmQKCWVsc2VpZiAoIGRhdGEgPT0gImFyMTUiICkgdGhlbgoJCWlmIElzUGVkSW5BbnlWZWhpY2xlKEdldFBsYXllclBlZCgtMSkpIHRoZW4KCQkJaWYgKCB0b2dBciApIHRoZW4KCQkJCUNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKCQkJCQlSZW1vdmVBbGxQZWRXZWFwb25zKEdldFBsYXllclBlZCgtMSksdHJ1ZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NPTUJBVFBJU1RPTCIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX1NUVU5HVU4iKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvblRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9GTEFTSExJR0hUIiksIDEwMDAsIGZhbHNlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fTklHSFRTVElDSyIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uQ29tcG9uZW50VG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NPTUJBVFBJU1RPTCIpLCBHZXRIYXNoS2V5KCJDT01QT05FTlRfQVRfUElfRkxTSCIpKQoJCQkJCVNldEN1cnJlbnRQZWRXZWFwb24oR2V0UGxheWVyUGVkKC0xKSwgIldFQVBPTl9VTkFSTUVEIiwgdHJ1ZSkKCQkJCQljaGF0UHJpbnQoICJZb3UgcHV0IHlvdXIgQVItMTUgYXdheSIgKQoJCQkJCWRvbnRXYW50KCkKCQkJCQl0b2dBciA9IGZhbHNlCgkJCQllbmQpCgkJCWVsc2UKCQkJCUNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKCQkJCQlSZW1vdmVBbGxQZWRXZWFwb25zKEdldFBsYXllclBlZCgtMSksdHJ1ZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NPTUJBVFBJU1RPTCIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX1NUVU5HVU4iKSwgMTAwMCwgZmFsc2UpCgkJCQkJR2l2ZVdlYXBvblRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9GTEFTSExJR0hUIiksIDEwMDAsIGZhbHNlKQoJCQkJCUdpdmVXZWFwb25Ub1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fTklHSFRTVElDSyIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NBUkJJTkVSSUZMRSIpLCAxMDAwLCBmYWxzZSkKCQkJCQlHaXZlV2VhcG9uQ29tcG9uZW50VG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NPTUJBVFBJU1RPTCIpLCBHZXRIYXNoS2V5KCJDT01QT05FTlRfQVRfUElfRkxTSCIpKQoJCQkJCUdpdmVXZWFwb25Db21wb25lbnRUb1BlZChHZXRQbGF5ZXJQZWQoLTEpLCBHZXRIYXNoS2V5KCJXRUFQT05fQ0FSQklORVJJRkxFIiksIEdldEhhc2hLZXkoIkNPTVBPTkVOVF9BVF9BUl9BRkdSSVAiKSkKCQkJCQlHaXZlV2VhcG9uQ29tcG9uZW50VG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgR2V0SGFzaEtleSgiV0VBUE9OX0NBUkJJTkVSSUZMRSIpLCBHZXRIYXNoS2V5KCJDT01QT05FTlRfQVRfQVJfRkxTSCIpKQoJCQkJCVNldEN1cnJlbnRQZWRXZWFwb24oR2V0UGxheWVyUGVkKC0xKSwgIldFQVBPTl9DQVJCSU5FUklGTEUiLCB0cnVlKQoJCQkJCWNoYXRQcmludCggIllvdSB1bmxvY2sgeW91ciBBUi0xNSIgKQoJCQkJCXdhbnQoIjB4ODNCRjAyNzgiKQoJCQkJCXRvZ0FyID0gdHJ1ZQoJCQkJZW5kKQoJCQllbmQKCQllbHNlCgkJCWNoYXRQcmludCggIkkgY2FuJ3QgcHVsbCBhbiBBUjE1IG91dCBvZiB0aGluIGFpci4uLiIgKQoJCWVuZAoJZWxzZWlmICggZGF0YSA9PSAiZ2VhciIgKSB0aGVuCgkJaWYgSXNQZWRJbkFueVZlaGljbGUoR2V0UGxheWVyUGVkKC0xKSkgdGhlbgoJCQlSZXF1ZXN0TW9kZWwoInNfbV95X2h3YXljb3BfMDEiKQoJCQl3aGlsZSBub3QgSGFzTW9kZWxMb2FkZWQoInNfbV95X2h3YXljb3BfMDEiKSBkbwoJCQkJQ2l0aXplbi5XYWl0KDApCgkJCWVuZAoJCQlTZXRQbGF5ZXJNb2RlbChQbGF5ZXJJZCgpLCBHZXRIYXNoS2V5KCJzX21feV9od2F5Y29wXzAxIikpCgkJCWZvciBrLCB3IGluIHBhaXJzKGdlYXIpIGRvCgkJCQlHaXZlV2VhcG9uVG9QZWQoR2V0UGxheWVyUGVkKC0xKSwgd1sxXSwgMTAwMCwgZmFsc2UsIGZhbHNlKQoJCQllbmQKCQkJR2l2ZVdlYXBvbkNvbXBvbmVudFRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9DT01CQVRQSVNUT0wiKSwgR2V0SGFzaEtleSgiQ09NUE9ORU5UX0FUX1BJX0ZMU0giKSkKCQkJR2l2ZVdlYXBvbkNvbXBvbmVudFRvUGVkKEdldFBsYXllclBlZCgtMSksIEdldEhhc2hLZXkoIldFQVBPTl9QVU1QU0hPVEdVTiIpLCBHZXRIYXNoS2V5KCJDT01QT05FTlRfQVRfQVJfRkxTSCIpKQoJCWVsc2UKCQkJY2hhdFByaW50KCAiSSBjYW4ndCBwdWxsIG15IEdlYXIgb3V0IG9mIHRoaW4gYWlyLi4uIiApCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJkMSIgKSB0aGVuIAoJCXNzKDEpIAoJZWxzZWlmICggZGF0YSA9PSAiZDIiICkgdGhlbiAKCQlzcygyKQoJZWxzZWlmICggZGF0YSA9PSAiZDMiICkgdGhlbiAKCQlzcygzKQoJZWxzZWlmICggZGF0YSA9PSAiZHMiICkgdGhlbgoJCWRzKCkKCWVsc2VpZiAoIGRhdGEgPT0gInRvZ1JhZGFyIiApIHRoZW4KCQlpZiBJc1BlZEluQW55VmVoaWNsZShHZXRQbGF5ZXJQZWQoLTEpKSB0aGVuCgkJCXRvZ1JhZGFyKCkKCQllbHNlCgkJCWNoYXRQcmludCggIkkgY2FuJ3QgcHVsbCBhIFJhZGFyIG91dCBvZiB0aGluIGFpci4uLiIgKQoJCWVuZAoJZWxzZWlmICggZGF0YSA9PSAiY3VmZiIgKSB0aGVuCgkJQ2l0aXplbi5DcmVhdGVUaHJlYWQoIGZ1bmN0aW9uKCkKCQkJQWRkVGV4dEVudHJ5KCdGTU1DX0tFWV9USVAxJywgIkVudGVyIHRoZSBDaXZpbGlhbidzIElEIikKCQkJRGlzcGxheU9uc2NyZWVuS2V5Ym9hcmQoIGZhbHNlLCAiRk1NQ19LRVlfVElQMSIsICIiLCAiIiwgIiIsICIiLCAiIiwgNCApCgkJCXdoaWxlIHRydWUgZG8gCgkJCQlpZiAoIFVwZGF0ZU9uc2NyZWVuS2V5Ym9hcmQoKSA9PSAxICkgdGhlbiAKCQkJCQlsb2NhbCBjdWZmU3RyID0gR2V0T25zY3JlZW5LZXlib2FyZFJlc3VsdCgpCgkJCQkJaWYgKCBzdHJpbmcubGVuKCBjdWZmU3RyICkgPiAwICkgdGhlbiAKCQkJCQkJbG9jYWwgY3VmZiA9IHRvbnVtYmVyKCBjdWZmU3RyICkKCgkJCQkJCWlmICggY3VmZiA8IDk5OSBhbmQgY3VmZiA+PSAxICkgdGhlbiAKCQkJCQkJCWxvY2FsIHRQSUQgPSBjdWZmU3RyCgkJCQkJCQlUcmlnZ2VyRXZlbnQoIkhhbmRjdWZmIiwgdFBJRCkKCQkJCQkJZW5kIAoKCQkJCQkJYnJlYWsKCQkJCQllbHNlIAoJCQkJCQlEaXNwbGF5T25zY3JlZW5LZXlib2FyZCggZmFsc2UsICIiLCAiIiwgIiIsICIiLCAiIiwgIiIsIDQgKQoJCQkJCWVuZCAKCQkJCWVsc2VpZiAoIFVwZGF0ZU9uc2NyZWVuS2V5Ym9hcmQoKSA9PSAyICkgdGhlbiAKCQkJCQlicmVhayAKCQkJCWVuZCAgCgoJCQkJQ2l0aXplbi5XYWl0KCAwICkKCQkJZW5kIAoJCWVuZCApCgllbHNlaWYgKCBkYXRhID09ICJ2ZDAiICkgdGhlbgkKCQlpZiAoIHZkMCApIHRoZW4KCQkJY2xvc2VEb29yKDApCgkJCXZkMCA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcigwKQoJCQl2ZDAgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDEiICkgdGhlbgkKCQlpZiAoIHZkMSApIHRoZW4KCQkJY2xvc2VEb29yKDEpCgkJCXZkMSA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcigxKQoJCQl2ZDEgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDIiICkgdGhlbgkKCQlpZiAoIHZkMiApIHRoZW4KCQkJY2xvc2VEb29yKDIpCgkJCXZkMiA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcigyKQoJCQl2ZDIgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDMiICkgdGhlbgkKCQlpZiAoIHZkMyApIHRoZW4KCQkJY2xvc2VEb29yKDMpCgkJCXZkMyA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcigzKQoJCQl2ZDMgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDQiICkgdGhlbgkKCQlpZiAoIHZkNCApIHRoZW4KCQkJY2xvc2VEb29yKDQpCgkJCXZkNSA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcig0KQoJCQl2ZDQgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDUiICkgdGhlbgkKCQlpZiAoIHZkNSApIHRoZW4KCQkJY2xvc2VEb29yKDUpCgkJCXZkNSA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcig1KQoJCQl2ZDUgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDYiICkgdGhlbgkKCQlpZiAoIHZkNiApIHRoZW4KCQkJY2xvc2VEb29yKDYpCgkJCXZkNiA9IGZhbHNlCgkJZWxzZQoJCQlvcGVuRG9vcig2KQoJCQl2ZDYgPSB0cnVlCgkJZW5kCgllbHNlaWYgKCBkYXRhID09ICJ2ZDciICkgdGhlbgkKCQlpZiAoIHZkNykgdGhlbgoJCQljbG9zZURvb3IoNykKCQkJdmQ3ID0gZmFsc2UKCQllbHNlCgkJCW9wZW5Eb29yKDcpCgkJCXZkNyA9IHRydWUKCQllbmQKCWVsc2VpZiAoIGRhdGEgPT0gInZkYyIgKSB0aGVuCQoJCWNsb3NlQWxsRG9vcnMoKQoJZWxzZWlmICggZGF0YSA9PSAiZW5naW5lIiApIHRoZW4KCQl0b2dnbGVFbmdpbmUoKQoJZWxzZWlmICggZGF0YSA9PSAid2luZG93cyIgKSB0aGVuCgkJdG9nZ2xlV2luZG93cygpCgllbHNlaWYgKCBkYXRhID09ICJleGl0IiApIHRoZW4gCgkJLS0gV2UgdG9nZ2xlIHRoZSBBY3Rpb25NZW51IGFuZCByZXR1cm4gaGVyZSwgb3RoZXJ3aXNlIHRoZSBmdW5jdGlvbiAKCQktLSBjYWxsIGJlbG93IHdvdWxkIGJlIGV4ZWN1dGVkIHRvbywgd2hpY2ggd291bGQganVzdCBvcGVuIHRoZSBtZW51IGFnYWluIAoJCVRvZ2dsZUFjdGlvbk1lbnUoKQoJCXJldHVybiAKCWVuZCAKIAoJLS0gVGhpcyB3aWxsIG9ubHkgYmUgY2FsbGVkIGlmIGFueSBidXR0b24gb3RoZXIgdGhhbiB0aGUgZXhpdCBidXR0b24gaXMgcHJlc3NlZAoJVG9nZ2xlQWN0aW9uTWVudSgpCmVuZCApCiAKIAotLVtbLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCglBY3Rpb25NZW51IENvbnRyb2wgYW5kIElucHV0IEJsb2NraW5nIAoJVGhpcyBpcyB0aGUgbWFpbiB3aGlsZSBsb29wIHRoYXQgb3BlbnMgdGhlIEFjdGlvbk1lbnUgb24ga2V5cHJlc3MuIEl0IAoJdXNlcyB0aGUgaW5wdXQgYmxvY2tpbmcgZm91bmQgaW4gdGhlIEVTIEJhbmtpbmcgcmVzb3VyY2UsIGNyZWRpdHMgdG8gCgl0aGUgYXV0aG9ycy4KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXV0tLQpDaXRpemVuLkNyZWF0ZVRocmVhZCggZnVuY3Rpb24oKQoJLS0gVGhpcyBpcyBqdXN0IGluIGNhc2UgdGhlIHJlc291cmNlcyByZXN0YXJ0ZWQgd2hpbHN0IHRoZSBOVUkgaXMgZm9jdXNlZC4gCglTZXROdWlGb2N1cyggZmFsc2UgKQogCgl3aGlsZSB0cnVlIGRvIAoJCS0tIENvbnRyb2wgSUQgMjAgaXMgdGhlICdaJyBrZXkgYnkgZGVmYXVsdCAKCQktLSBVc2UgaHR0cHM6Ly93Li4uY29udGVudC1hdmFpbGFibGUtdG8tYXV0aG9yLW9ubHkuLi5tLm5ldC93aWtpL0NvbnRyb2xzIHRvIGZpbmQgYSBkaWZmZXJlbnQga2V5IAoJCS0tIE5vdyBzZXQgdG8gTQoJCWlmICggSXNDb250cm9sSnVzdFByZXNzZWQoIDEsIDI0NCApICkgdGhlbiAKCQkJVG9nZ2xlQWN0aW9uTWVudSgpCgkJZW5kIAogCgkgICAgaWYgKCBtZW51RW5hYmxlZCApIHRoZW4KICAgICAgICAgICAgbG9jYWwgcGVkID0gR2V0UGxheWVyUGVkKCAtMSApCQogCiAgICAgICAgICAgIERpc2FibGVDb250cm9sQWN0aW9uKCAwLCAxLCB0cnVlICkgLS0gTG9va0xlZnRSaWdodAogICAgICAgICAgICBEaXNhYmxlQ29udHJvbEFjdGlvbiggMCwgMiwgdHJ1ZSApIC0tIExvb2tVcERvd24KICAgICAgICAgICAgRGlzYWJsZUNvbnRyb2xBY3Rpb24oIDAsIDI0LCB0cnVlICkgLS0gQXR0YWNrCiAgICAgICAgICAgIERpc2FibGVQbGF5ZXJGaXJpbmcoIHBlZCwgdHJ1ZSApIC0tIERpc2FibGUgd2VhcG9uIGZpcmluZwogICAgICAgICAgICBEaXNhYmxlQ29udHJvbEFjdGlvbiggMCwgMTQyLCB0cnVlICkgLS0gTWVsZWVBdHRhY2tBbHRlcm5hdGUKICAgICAgICAgICAgRGlzYWJsZUNvbnRyb2xBY3Rpb24oIDAsIDEwNiwgdHJ1ZSApIC0tIFZlaGljbGVNb3VzZUNvbnRyb2xPdmVycmlkZQogICAgICAgIGVuZAogCgkJQ2l0aXplbi5XYWl0KCAwICkKCWVuZCAKZW5kICkKIApmdW5jdGlvbiBjaGF0UHJpbnQoIG1zZyApCglUcmlnZ2VyRXZlbnQoICdjaGF0TWVzc2FnZScsICJWaXNpb25hcnlSUCIsIHsgMjU1LCAyNTUsIDI1NSB9LCBtc2cgKQplbmQgCiAKZnVuY3Rpb24gc3MoIG51bSApCglUcmlnZ2VyRXZlbnQoICdTcGlrZXN0cmlwczpTcGF3blNwaWtlcycsIHtpc1Jlc3RyaWN0ZWQgPSBTcGlrZUNvbmZpZy5QZWRSZXN0cmljdGlvbiwgcGVkTGlzdCA9IFNwaWtlQ29uZmlnLlBlZHNMaXN0LH0sIG51bSApCmVuZCAKCmZ1bmN0aW9uIGRzKCkKCVRyaWdnZXJFdmVudCggJ1NwaWtlc3RyaXBzOlJlbW92ZVNwaWtlcycpCmVuZCAKCmZ1bmN0aW9uIHRvZ1JhZGFyKCkKCVRyaWdnZXJFdmVudCggJ3drOnJhZGFyUkMnKQplbmQgCgpmdW5jdGlvbiB3YW50KHdlYSkKCVRyaWdnZXJFdmVudCggJ1BvbGljZVZlaGljbGVXZWFwb25EZWxldGVyOmdldHRpbmdBR3VuJywgd2VhKQplbmQgCgpmdW5jdGlvbiBkb250V2FudCh3ZWEpCglUcmlnZ2VyRXZlbnQoICdQb2xpY2VWZWhpY2xlV2VhcG9uRGVsZXRlcjpub3RHZXR0aW5nQUd1bicpCmVuZCAKCmZ1bmN0aW9uIG9wZW5Eb29yKHZkKQoJbG9jYWwgVmVoID0gR2V0VmVoaWNsZVBlZElzVXNpbmcoR2V0UGxheWVyUGVkKC0xKSkKCVNldFZlaGljbGVEb29yT3BlbihWZWgsIHZkLCBmYWxzZSwgZmFsc2UpCmVuZAoKZnVuY3Rpb24gY2xvc2VEb29yKHZkKQoJbG9jYWwgVmVoID0gR2V0VmVoaWNsZVBlZElzVXNpbmcoR2V0UGxheWVyUGVkKC0xKSkKCVNldFZlaGljbGVEb29yU2h1dChWZWgsIHZkLCBmYWxzZSkKZW5kCgpmdW5jdGlvbiBjbG9zZUFsbERvb3JzKCkKCWxvY2FsIFZlaCA9IEdldFZlaGljbGVQZWRJc1VzaW5nKEdldFBsYXllclBlZCgtMSkpCglTZXRWZWhpY2xlRG9vclNodXQoVmVoLCAwLCBmYWxzZSkKCVNldFZlaGljbGVEb29yU2h1dChWZWgsIDEsIGZhbHNlKQoJU2V0VmVoaWNsZURvb3JTaHV0KFZlaCwgMiwgZmFsc2UpCglTZXRWZWhpY2xlRG9vclNodXQoVmVoLCAzLCBmYWxzZSkKCVNldFZlaGljbGVEb29yU2h1dChWZWgsIDQsIGZhbHNlKQoJU2V0VmVoaWNsZURvb3JTaHV0KFZlaCwgNSwgZmFsc2UpCglTZXRWZWhpY2xlRG9vclNodXQoVmVoLCA2LCBmYWxzZSkKCVNldFZlaGljbGVEb29yU2h1dChWZWgsIDcsIGZhbHNlKQplbmQKCmZ1bmN0aW9uIHRvZ2dsZUVuZ2luZSgpCiAgICBsb2NhbCB2ZWhpY2xlID0gR2V0VmVoaWNsZVBlZElzSW4oUGxheWVyUGVkSWQoKSwgZmFsc2UpCiAgICBpZiB2ZWhpY2xlIH49IG5pbCBhbmQgdmVoaWNsZSB+PSAwIGFuZCBHZXRQZWRJblZlaGljbGVTZWF0KHZlaGljbGUsIDApIHRoZW4KICAgICAgICBTZXRWZWhpY2xlRW5naW5lT24odmVoaWNsZSwgKG5vdCBHZXRJc1ZlaGljbGVFbmdpbmVSdW5uaW5nKHZlaGljbGUpKSwgZmFsc2UsIHRydWUpCiAgICBlbmQKZW5kCgpmdW5jdGlvbiB0b2dnbGVXaW5kb3dzKCkKCWlmICggdG9nV2luICkgdGhlbgoJCVJvbGVVcFdpbmRvdyhwbGF5ZXJDYXIsIDApCgkJUm9sZVVwV2luZG93KHBsYXllckNhciwgMSkKCQlSb2xlVXBXaW5kb3cocGxheWVyQ2FyLCAyKQoJCVJvbGVVcFdpbmRvdyhwbGF5ZXJDYXIsIDMpCgkJdG9nV2luIGZhbHNlCgllbHNlCgkJbG9jYWwgcGxheWVyQ2FyID0gR2V0VmVoaWNsZVBlZElzSW4ocGxheWVyUGVkLCBmYWxzZSkKCQlSb2xsRG93bldpbmRvd3MocGxheWVyQ2FyKQoJCXRvZ1dpbiB0cnVlCgllbmQKZW5kCgpmdW5jdGlvbiB0YWJsZWxlbmd0aChUKQogIGxvY2FsIGNvdW50ID0gMAogIGZvciBfIGluIHBhaXJzKFQpIGRvIGNvdW50ID0gY291bnQgKyAxIGVuZAogIHJldHVybiBjb3VudAplbmQKCi0tW1sgTG9vcGVkIFRocmVhZCBdXS0tCkNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKCXdoaWxlIHRydWUgZG8KCQlDaXRpemVuLldhaXQoMCkKIAoJCWlmIElzUGVkSW5BbnlWZWhpY2xlKEdldFBsYXllclBlZChQbGF5ZXJJZCgpKSwgZmFsc2UpIHRoZW4KCQkJbG9jYWwgdmVoaWNsZSA9IEdldFZlaGljbGVQZWRJc0luKEdldFBsYXllclBlZChQbGF5ZXJJZCgpKSwgZmFsc2UpCgkJCWxvY2FsIHZlaGljbGVQb3MgPSBHZXRFbnRpdHlDb29yZHModmVoaWNsZSwgZmFsc2UpCgkJCWxvY2FsIHNwaWtlcyA9IEdldENsb3Nlc3RPYmplY3RPZlR5cGUodmVoaWNsZVBvcy54LCB2ZWhpY2xlUG9zLnksIHZlaGljbGVQb3MueiwgNzUuMCwgR2V0SGFzaEtleSgiUF9sZF9zdGluZ2VyX3MiKSwgZmFsc2UsIDEsIDEpCgkJCWxvY2FsIHNwaWtlc0Nvb3JkcyA9IEdldEVudGl0eUNvb3JkcyhzcGlrZXMsIGZhbHNlKQoJCQlsb2NhbCBkaXN0YW5jZSA9IFZkaXN0KHZlaGljbGVQb3MueCwgdmVoaWNsZVBvcy55LCB2ZWhpY2xlUG9zLnosIHNwaWtlc0Nvb3Jkcy54LCBzcGlrZXNDb29yZHMueSwgc3Bpa2VzQ29vcmRzLnopCgkJCWlmIGRpc3RhbmNlIDw9IDc1LjAgdGhlbgoJCQkJQ2hlY2tEaXN0YW5jZVRvU3RyaXBzKCkKCQkJZW5kCgkJZW5kCgllbmQKZW5kKQogClJlZ2lzdGVyQ29tbWFuZCgic3Bhd24iLCBmdW5jdGlvbihzb3VyY2UsIGFyZ3MsIHN0cmluZykKCVNwYXduU3Bpa2VzKCkKZW5kLCBmYWxzZSkKIApSZWdpc3Rlck5ldEV2ZW50KCJTcGlrZXN0cmlwczpTcGF3blNwaWtlcyIpCkFkZEV2ZW50SGFuZGxlcigiU3Bpa2VzdHJpcHM6U3Bhd25TcGlrZXMiLCBmdW5jdGlvbihjb25maWcsIGFtb3VudCkKCWlmIGNvbmZpZy5pc1Jlc3RyaWN0ZWQgdGhlbgoJCWlmIENoZWNrUGVkUmVzdHJpY3Rpb24oR2V0UGxheWVyUGVkKFBsYXllcklkKCkpLCBjb25maWcucGVkTGlzdCkgdGhlbgoJCQlmb3IgYSA9IDEsIGFtb3VudCBkbwoJCQkJbG9jYWwgcGx5Q29vcmRzID0gR2V0T2Zmc2V0RnJvbUVudGl0eUluV29ybGRDb29yZHMoR2V0UGxheWVyUGVkKFBsYXllcklkKCkpLCAwLjAsIDMuMCAqIGEgKyAwLjUsIDAuMCkKCQkJCWxvY2FsIHBseUhlYWQgPSBHZXRFbnRpdHlIZWFkaW5nKEdldFBsYXllclBlZChQbGF5ZXJJZCgpKSkKCQkJCWxvY2FsIHNwaWtlID0gQ3JlYXRlT2JqZWN0KEdldEhhc2hLZXkoIlBfbGRfc3Rpbmdlcl9zIiksIHBseUNvb3Jkcy54LCBwbHlDb29yZHMueSwgcGx5Q29vcmRzLnosIHRydWUsIDEsIHRydWUpCgkJCQlsb2NhbCBzcGlrZUhlaWdodCA9IEdldEVudGl0eUhlaWdodEFib3ZlR3JvdW5kKHNwaWtlKQoJCQkJU2V0RW50aXR5Q29vcmRzKHNwaWtlLCBwbHlDb29yZHMueCwgcGx5Q29vcmRzLnksIHBseUNvb3Jkcy56IC0gc3Bpa2VIZWlnaHQgKyAwLjA1LCAwLjAsIDAuMCwgMC4wLCAwLjApCgkJCQlTZXRFbnRpdHlIZWFkaW5nKHNwaWtlLCBwbHlIZWFkKQoJCQkJU2V0RW50aXR5QXNNaXNzaW9uRW50aXR5KHNwaWtlLCAxLCAxKQoJCQkJdGFibGUuaW5zZXJ0KFNwYXduZWRTcGlrZXMsIHNwaWtlKQoJCQkJU3Bpa2VzU3Bhd25lZCA9IHRydWUKCQkJZW5kCgkJZWxzZQoJCQljaGF0UHJpbnQoICJXaGVyZSB0aGUgaGVsbCBhbSBJIG1lYW50IHRvIGdldCBTcGlrZSBTdHJpcHMgZnJvbT8hIiApCgkJZW5kCgllbHNlCgkJZm9yIGIgPSAxLCBhbW91bnQgZG8KCQkJbG9jYWwgcGx5Q29vcmRzID0gR2V0T2Zmc2V0RnJvbUVudGl0eUluV29ybGRDb29yZHMoR2V0UGxheWVyUGVkKFBsYXllcklkKCkpLCAwLjAsIDMuMCAqIGIgKyAwLjUsIDAuMCkKCQkJbG9jYWwgcGx5SGVhZCA9IEdldEVudGl0eUhlYWRpbmcoR2V0UGxheWVyUGVkKFBsYXllcklkKCkpKQoJCQlsb2NhbCBzcGlrZSA9IENyZWF0ZU9iamVjdChHZXRIYXNoS2V5KCJQX2xkX3N0aW5nZXJfcyIpLCBwbHlDb29yZHMueCwgcGx5Q29vcmRzLnksIHBseUNvb3Jkcy56LCB0cnVlLCAxLCB0cnVlKQoJCQlsb2NhbCBzcGlrZUhlaWdodCA9IEdldEVudGl0eUhlaWdodEFib3ZlR3JvdW5kKHNwaWtlKQoJCQlTZXRFbnRpdHlDb29yZHMoc3Bpa2UsIHBseUNvb3Jkcy54LCBwbHlDb29yZHMueSwgcGx5Q29vcmRzLnogLSBzcGlrZUhlaWdodCArIDAuMDUsIDAuMCwgMC4wLCAwLjAsIDAuMCkKCQkJU2V0RW50aXR5SGVhZGluZyhzcGlrZSwgcGx5SGVhZCkKCQkJU2V0RW50aXR5QXNNaXNzaW9uRW50aXR5KHNwaWtlLCAxLCAxKQoJCQlTZXRFbnRpdHlDb2xsaXNpb24oc3Bpa2UsIGZhbHNlLCBmYWxzZSkKCQkJdGFibGUuaW5zZXJ0KFNwYXduZWRTcGlrZXMsIHNwaWtlKQoJCQlTcGlrZXNTcGF3bmVkID0gdHJ1ZQoJCWVuZAoJZW5kCmVuZCkKIApSZWdpc3Rlck5ldEV2ZW50KCJTcGlrZXN0cmlwczpSZW1vdmVTcGlrZXMiKQpBZGRFdmVudEhhbmRsZXIoIlNwaWtlc3RyaXBzOlJlbW92ZVNwaWtlcyIsIGZ1bmN0aW9uKCkKCWlmIFNwaWtlc1NwYXduZWQgdGhlbgoJCWZvciBpID0gMSwgI1NwYXduZWRTcGlrZXMgZG8KCQkJRGVsZXRlRW50aXR5KFNwYXduZWRTcGlrZXNbaV0pCgkJCVNwYXduZWRTcGlrZXNbaV0gPSBuaWwKCQkJU3Bpa2VzU3Bhd25lZCA9IGZhbHNlCgkJZW5kCgllbmQKZW5kKQogCmZ1bmN0aW9uIENoZWNrRGlzdGFuY2VUb1N0cmlwcygpCglsb2NhbCB2ZWhpY2xlID0gR2V0VmVoaWNsZVBlZElzSW4oR2V0UGxheWVyUGVkKFBsYXllcklkKCkpLCBmYWxzZSkKCUZyb250TGVmdFRpcmUodmVoaWNsZSkKCUZyb250UmlnaHRUaXJlKHZlaGljbGUpCglCYWNrTGVmdFRpcmUodmVoaWNsZSkKCUJhY2tSaWdodFRpcmUodmVoaWNsZSkKZW5kCiAKZnVuY3Rpb24gRnJvbnRMZWZ0VGlyZSh2ZWhpY2xlKQoJbG9jYWwgdGlyZVBvc2l0aW9uID0gR2V0V29ybGRQb3NpdGlvbk9mRW50aXR5Qm9uZSh2ZWhpY2xlLCBHZXRFbnRpdHlCb25lSW5kZXhCeU5hbWUodmVoaWNsZSwgIndoZWVsX2xmIikpCglsb2NhbCBzcGlrZXN0cmlwID0gR2V0Q2xvc2VzdE9iamVjdE9mVHlwZSh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCAxNS4wLCBHZXRIYXNoS2V5KCJQX2xkX3N0aW5nZXJfcyIpLCBmYWxzZSwgMSwgMSkKCWxvY2FsIHNwaWtlQ29vcmRzID0gR2V0RW50aXR5Q29vcmRzKHNwaWtlc3RyaXAsIGZhbHNlKQoJbG9jYWwgZGlzdGFuY2UgPSBWZGlzdCh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCBzcGlrZUNvb3Jkcy54LCBzcGlrZUNvb3Jkcy55LCBzcGlrZUNvb3Jkcy56KQogCglpZiBkaXN0YW5jZSA8IDEuOCB0aGVuCgkJaWYgbm90IElzVmVoaWNsZVR5cmVCdXJzdCh2ZWhpY2xlLCAwLCBmYWxzZSkgYW5kIG5vdCBJc1ZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSwgMCwgdHJ1ZSkgdGhlbgoJCQlTZXRWZWhpY2xlVHlyZUJ1cnN0KHZlaGljbGUsIDAsIGZhbHNlLCAxMDAwLjApCgkJZW5kCgllbmQKZW5kCiAKZnVuY3Rpb24gRnJvbnRSaWdodFRpcmUodmVoaWNsZSkKCWxvY2FsIHRpcmVQb3NpdGlvbiA9IEdldFdvcmxkUG9zaXRpb25PZkVudGl0eUJvbmUodmVoaWNsZSwgR2V0RW50aXR5Qm9uZUluZGV4QnlOYW1lKHZlaGljbGUsICJ3aGVlbF9yZiIpKQoJbG9jYWwgc3Bpa2VzdHJpcCA9IEdldENsb3Nlc3RPYmplY3RPZlR5cGUodGlyZVBvc2l0aW9uLngsIHRpcmVQb3NpdGlvbi55LCB0aXJlUG9zaXRpb24ueiwgMTUuMCwgR2V0SGFzaEtleSgiUF9sZF9zdGluZ2VyX3MiKSwgZmFsc2UsIDEsIDEpCglsb2NhbCBzcGlrZUNvb3JkcyA9IEdldEVudGl0eUNvb3JkcyhzcGlrZXN0cmlwLCBmYWxzZSkKCWxvY2FsIGRpc3RhbmNlID0gVmRpc3QodGlyZVBvc2l0aW9uLngsIHRpcmVQb3NpdGlvbi55LCB0aXJlUG9zaXRpb24ueiwgc3Bpa2VDb29yZHMueCwgc3Bpa2VDb29yZHMueSwgc3Bpa2VDb29yZHMueikKIAoJaWYgZGlzdGFuY2UgPCAxLjggdGhlbgoJCWlmIG5vdCBJc1ZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSwgMSwgZmFsc2UpIGFuZCBub3QgSXNWZWhpY2xlVHlyZUJ1cnN0KHZlaGljbGUsIDEsIHRydWUpIHRoZW4KCQkJU2V0VmVoaWNsZVR5cmVCdXJzdCh2ZWhpY2xlLCAxLCBmYWxzZSwgMTAwMC4wKQoJCWVuZAoJZW5kCmVuZAogCmZ1bmN0aW9uIEJhY2tMZWZ0VGlyZSh2ZWhpY2xlKQoJbG9jYWwgdGlyZVBvc2l0aW9uID0gR2V0V29ybGRQb3NpdGlvbk9mRW50aXR5Qm9uZSh2ZWhpY2xlLCBHZXRFbnRpdHlCb25lSW5kZXhCeU5hbWUodmVoaWNsZSwgIndoZWVsX2xyIikpCglsb2NhbCBzcGlrZXN0cmlwID0gR2V0Q2xvc2VzdE9iamVjdE9mVHlwZSh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCAxNS4wLCBHZXRIYXNoS2V5KCJQX2xkX3N0aW5nZXJfcyIpLCBmYWxzZSwgMSwgMSkKCWxvY2FsIHNwaWtlQ29vcmRzID0gR2V0RW50aXR5Q29vcmRzKHNwaWtlc3RyaXAsIGZhbHNlKQoJbG9jYWwgZGlzdGFuY2UgPSBWZGlzdCh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCBzcGlrZUNvb3Jkcy54LCBzcGlrZUNvb3Jkcy55LCBzcGlrZUNvb3Jkcy56KQogCglpZiBkaXN0YW5jZSA8IDEuOCB0aGVuCgkJaWYgbm90IElzVmVoaWNsZVR5cmVCdXJzdCh2ZWhpY2xlLCA0LCBmYWxzZSkgYW5kIG5vdCBJc1ZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSwgNCwgdHJ1ZSkgdGhlbgoJCQlTZXRWZWhpY2xlVHlyZUJ1cnN0KHZlaGljbGUsIDQsIGZhbHNlLCAxMDAwLjApCgkJCVNldFZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSAsIDIsIGZhbHNlLCAxMDAwLjApCgkJZW5kCgllbmQKZW5kCiAKZnVuY3Rpb24gQmFja1JpZ2h0VGlyZSh2ZWhpY2xlKQoJbG9jYWwgdGlyZVBvc2l0aW9uID0gR2V0V29ybGRQb3NpdGlvbk9mRW50aXR5Qm9uZSh2ZWhpY2xlLCBHZXRFbnRpdHlCb25lSW5kZXhCeU5hbWUodmVoaWNsZSwgIndoZWVsX3JyIikpCglsb2NhbCBzcGlrZXN0cmlwID0gR2V0Q2xvc2VzdE9iamVjdE9mVHlwZSh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCAxNS4wLCBHZXRIYXNoS2V5KCJQX2xkX3N0aW5nZXJfcyIpLCBmYWxzZSwgMSwgMSkKCWxvY2FsIHNwaWtlQ29vcmRzID0gR2V0RW50aXR5Q29vcmRzKHNwaWtlc3RyaXAsIGZhbHNlKQoJbG9jYWwgZGlzdGFuY2UgPSBWZGlzdCh0aXJlUG9zaXRpb24ueCwgdGlyZVBvc2l0aW9uLnksIHRpcmVQb3NpdGlvbi56LCBzcGlrZUNvb3Jkcy54LCBzcGlrZUNvb3Jkcy55LCBzcGlrZUNvb3Jkcy56KQogCglpZiBkaXN0YW5jZSA8IDEuOCB0aGVuCgkJaWYgbm90IElzVmVoaWNsZVR5cmVCdXJzdCh2ZWhpY2xlLCA1LCBmYWxzZSkgYW5kIG5vdCBJc1ZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSwgNSwgdHJ1ZSkgdGhlbgoJCQlTZXRWZWhpY2xlVHlyZUJ1cnN0KHZlaGljbGUsIDUsIGZhbHNlLCAxMDAwLjApCgkJCVNldFZlaGljbGVUeXJlQnVyc3QodmVoaWNsZSAsIDMsIGZhbHNlLCAxMDAwLjApCgkJZW5kCgllbmQKZW5kCiAKZnVuY3Rpb24gQ2hlY2tQZWRSZXN0cmljdGlvbihwZWQsIFBlZExpc3QpCglmb3IgaSA9IDEsICNQZWRMaXN0IGRvCgkJcHJpbnQodG9zdHJpbmcoR2V0SGFzaEtleShQZWRMaXN0W2ldKSkpCgkJaWYgR2V0SGFzaEtleShQZWRMaXN0W2ldKSA9PSBHZXRFbnRpdHlNb2RlbChwZWQpIHRoZW4KCQkJcmV0dXJuIHRydWUKCQllbmQKCWVuZAoJcmV0dXJuIGZhbHNlCmVuZAogCkNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKCXdoaWxlIHRydWUgZG8KCQlDaXRpemVuLldhaXQoMCkKCQlpZiBTcGlrZXNTcGF3bmVkIHRoZW4KCQkJZm9yIGkgPSAxLCAjU3Bhd25lZFNwaWtlcyBkbwoJCQkJRnJlZXplRW50aXR5UG9zaXRpb24oU3Bhd25lZFNwaWtlc1tpXSwgdHJ1ZSkKCQkJZW5kCgkJZW5kCgllbmQKZW5kKQ==