ESX = nil
local PlayerData = {}
local GUI = {}
GUI.Time = 0
local HasAlreadyEnteredMarker = false
local LastZone = nil
local CurrentAction = nil
local CurrentActionMsg = ''
local CurrentActionData = {}
local OnJob = false
local TargetCoords = nil
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
Citizen.Wait(0)
end
end)
function OpenLumberBossMenu()
if Config.EnablePlayerManagement and PlayerData.job ~= nil and PlayerData.job.grade_name ~= 'boss' then
local elements = {
{label = 'Sortir Véhicule', value = 'vehicle_list'},
{label = 'Tenue de travail', value = 'cloakroom'},
{label = 'Tenue civile', value = 'cloakroom2'}
}
if Config.EnablePlayerManagement and PlayerData.job ~= nil and PlayerData.job.grade_name == 'boss' then
table.insert(elements, {label = 'Retirer argent société', value = 'withdraw_society_money'})
table.insert(elements, {label = 'Déposer argent ', value = 'deposit_money'})
table.insert(elements, {label = 'Blanchir argent', value = 'wash_money'})
end
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open(
'default', GetCurrentResourceName(), 'mecano_actions',
{
title = 'Mecano',
elements = elements
},
function(data, menu)
if data.current.value == 'withdraw_society_money' then
ESX.UI.Menu.Open(
'dialog', GetCurrentResourceName(), 'withdraw_society_money_amount',
{
title = 'Montant du retrait'
},
function(data, menu)
local amount = tonumber(data.value)
if amount == nil then
ESX.ShowNotification('Montant invalide')
else
menu.close()
TriggerServerEvent('esx_society:withdrawMoney', 'mecano', amount)
end
end,
function(data, menu)
menu.close()
end
)
end
if data.current.value == 'deposit_money' then
ESX.UI.Menu.Open(
'dialog', GetCurrentResourceName(), 'deposit_money_amount',
{
title = 'Montant du dépôt'
},
function(data, menu)
local amount = tonumber(data.value)
if amount == nil then
ESX.ShowNotification('Montant invalide')
else
menu.close()
TriggerServerEvent('esx_society:depositMoney', 'mecano', amount)
end
end,
function(data, menu)
menu.close()
end
)
end
if data.current.value == 'wash_money' then
ESX.UI.Menu.Open(
'dialog', GetCurrentResourceName(), 'wash_money_amount',
{
title = 'Montant à blanchir'
},
function(data, menu)
local amount = tonumber(data.value)
if amount == nil then
ESX.ShowNotification('Montant invalide')
else
menu.close()
TriggerServerEvent('esx_society:washMoney', 'mecano', amount)
end
end,
function(data, menu)
menu.close()
end
)
end
end,
function(data, menu)
menu.close()
CurrentAction = 'lumber_boss_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au menu.'
CurrentActionData = {}
end
)
end
function OpenLumberVehicleMenu()
local elements = {
{label = 'Camion Phantom', value = 'phantom', trailer = 'trailers'}
}
if Config.EnablePlayerManagement and PlayerData.job ~= nil and
(PlayerData.job.grade_name == 'boss' or PlayerData.job.grade_name == 'employee' or PlayerData.job.grade_name == 'responsable') then
table.insert(elements, {label = 'Camion Packer', value = 'packer', trailer = 'trailers'})
end
if Config.EnablePlayerManagement and PlayerData.job ~= nil and
(PlayerData.job.grade_name == 'boss' or PlayerData.job.grade_name == 'responsable') then
table.insert(elements, {label = 'Camion Fast Phantom', value = 'phantom3', trailer = 'trailers'})
end
if Config.EnablePlayerManagement and PlayerData.job ~= nil and
(PlayerData.job.grade_name == 'boss') then
table.insert(elements, {label = 'Pickup Bison', value = 'bison3', trailer = 'none'})
end
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open(
'default', GetCurrentResourceName(), 'spawn_vehicle',
{
title = 'Véhicule de service',
elements = elements
},
function(data, menu)
for i=1, #elements, 1 do
if Config.MaxInService == -1 then
local playerPed = GetPlayerPed(-1)
local coords = Config.Zones.VehicleSpawnPoint.Pos
ESX.Game.SpawnVehicle(data.current.value, coords, 90.0, function(vehicle)
if data.current.trailer ~= "none" then
ESX.Game.SpawnVehicle(data.current.rem, coords, 90.0, function(trailer)
AttachVehicleToTrailer(vehicle, trailer, 1.1)
end)
end
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
end)
break
else
ESX.TriggerServerCallback('esx_service:enableService', function(canTakeService, maxInService, inServiceCount)
if canTakeService then
local playerPed = GetPlayerPed(-1)
local coords = Config.Zones.VehicleSpawnPoint.Pos
ESX.Game.SpawnVehicle(data.current.value, coords, 90.0, function(vehicle)
if data.current.trailer ~= "none" then
ESX.Game.SpawnVehicle(data.current.rem, coords, 90.0, function(trailer)
AttachVehicleToTrailer(vehicle, trailer, 1.1)
end)
end
TaskWarpPedIntoVehicle(playerPed, vehicle, -1)
end)
else
ESX.ShowNotification('Service complet : ' .. inServiceCount .. '/' .. maxInService)
end
end, 'lumberjack')
break
end
end
menu.close()
end,
function(data, menu)
menu.close()
CurrentAction = 'spawn_vehicle_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au Garage.'
CurrentActionData = {}
end
)
end
function OpenLumberCloakroomtMenu()
local elements = {
{label = 'Tenue de travail', value = 'cloakroom'},
{label = 'Tenue civile', value = 'cloakroom2'}
}
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open(
'default', GetCurrentResourceName(), 'lumber_cloakroom',
{
title = 'Etabli',
elements = elements
},
function(data, menu)
if data.current.value == 'cloakroom' then
menu.close()
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
if skin.sex == 0 then
TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_male)
else
TriggerEvent('skinchanger:loadClothes', skin, jobSkin.skin_female)
end
end)
end
if data.current.value == 'cloakroom2' then
menu.close()
ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin)
TriggerEvent('skinchanger:loadSkin', skin)
end)
end
end,
function(data, menu)
menu.close()
CurrentAction = 'lumber_cloakroom_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au véstiaire.'
CurrentActionData = {}
end
)
end
function OpenMobileLumberActionsMenu()
ESX.UI.Menu.CloseAll()
ESX.UI.Menu.Open(
'default', GetCurrentResourceName(), 'mobile_lumber_actions',
{
title = 'Mécano',
elements = {
{label = 'Facuration', value = 'billing'}
}
},
function(data, menu)
if data.current.value == 'billing' then
ESX.UI.Menu.Open(
'dialog', GetCurrentResourceName(), 'billing',
{
title = 'Montant de la facture'
},
function(data, menu)
local amount = tonumber(data.value)
if amount == nil then
ESX.ShowNotification('Montant invalide')
else
menu.close()
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer()
if closestPlayer == -1 or closestDistance > 3.0 then
ESX.ShowNotification('Aucun joueur à proximité')
else
TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(closestPlayer), 'society_lumberjack', 'Bucheron', amount)
end
end
end,
function(data, menu)
menu.close()
end
)
end
end,
function(data, menu)
menu.close()
end
)
end
RegisterNetEvent('esx:playerLoaded')
AddEventHandler('esx:playerLoaded', function(xPlayer)
PlayerData = xPlayer
end)
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
PlayerData.job = job
end)
AddEventHandler('esx_lumberjackjob:hasEnteredMarker', function(zone)
if zone == 'Bossroom' then
CurrentAction = 'lumber_boss_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au menu Patron.'
CurrentActionData = {}
end
if zone == 'Cloakroom' then
CurrentAction = 'lumber_cloakroom_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au véstiaire.'
CurrentActionData = {}
end
if zone == 'Wood' then
CurrentAction = 'harvest_wood'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour récolter du bois.'
CurrentActionData = {}
end
if zone == 'CuttedWood' then
CurrentAction = 'transform_cuttedwood'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour couper du bois.'
CurrentActionData = {}
end
if zone == 'Planks' then
CurrentAction = 'harvest_plank'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour récupérer des planches.'
CurrentActionData = {}
end
if zone == 'Delivery' then
CurrentAction = 'resell'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour vendre des planches.'
CurrentActionData = {}
end
if zone == 'VehicleSpawner' then
CurrentAction = 'spawn_vehicle_menu'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour accéder au garage.'
CurrentActionData = {}
end
if zone == 'VehicleDeleter' then
local playerPed = GetPlayerPed(-1)
if IsPedInAnyVehicle(playerPed, false) then
CurrentAction = 'delete_vehicle'
CurrentActionMsg = 'Appuyez sur ~INPUT_CONTEXT~ pour ranger le véhicule.'
CurrentActionData = {}
end
end
end)
AddEventHandler('esx_lumberjackjob:hasExitedMarker', function(zone)
if zone == 'Wood' then
TriggerServerEvent('esx_lumberjackjob:stopHarvestWood')
end
if zone == 'CuttedWood' then
TriggerServerEvent('esx_lumberjackjob:stopCutingWood')
end
if zone == 'Planks' then
TriggerServerEvent('esx_lumberjackjob:stopPackagePlank')
end
if zone == 'Delivery' then
TriggerServerEvent('esx_lumberjackjob:stopResell')
end
CurrentAction = nil
ESX.UI.Menu.CloseAll()
end)
RegisterNetEvent('esx_phone:loaded')
AddEventHandler('esx_phone:loaded', function(phoneNumber, contacts)
local specialContact = {
name = 'Bucheron',
number = 'bucheron',
base64Icon = 'data:image/png;base64,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'
}
TriggerEvent('esx_phone:addSpecialContact', specialContact.name, specialContact.number, specialContact.base64Icon)
end)
-- Create Blips
Citizen.CreateThread(function()
local blip = AddBlipForCoord(Config.Zones.Cloakroom.Pos.x, Config.Zones.Cloakroom.Pos.y, Config.Zones.Cloakroom.Pos.z)
SetBlipSprite (blip, 237)
SetBlipDisplay(blip, 4)
SetBlipScale (blip, 1.0)
SetBlipColour (blip, 5)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("Dépôt Bucheron")
EndTextCommandSetBlipName(blip)
end)
Citizen.CreateThread(function()
local blip = AddBlipForCoord(Config.Zones.Wood.Pos.x, Config.Zones.Wood.Pos.y, Config.Zones.Wood.Pos.z)
SetBlipSprite (blip, 237)
SetBlipDisplay(blip, 4)
SetBlipScale (blip, 1.0)
SetBlipColour (blip, 5)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName("STRING")
AddTextComponentString("Scierie")
EndTextCommandSetBlipName(blip)
end)
-- Display markers
Citizen.CreateThread(function()
while true do
Wait(0)
if PlayerData.job ~= nil and PlayerData.job.name == 'lumberjack' then
local coords = GetEntityCoords(GetPlayerPed(-1))
for k,v in pairs(Config.Zones) do
if(v.Type ~= -1 and GetDistanceBetweenCoords(coords, v.Pos.x, v.Pos.y, v.Pos.z, true) < Config.DrawDistance) then
DrawMarker(v.Type, v.Pos.x, v.Pos.y, v.Pos.z, 0.0, 0.0, 0.0, 0, 0.0, 0.0, v.Size.x, v.Size.y, v.Size.z, v.Color.r, v.Color.g, v.Color.b, 100, false, true, 2, false, false, false, false)
end
end
end
end
end)
-- Enter / Exit marker events
Citizen.CreateThread(function()
while true do
Wait(0)
if PlayerData.job ~= nil and PlayerData.job.name == 'lumberjack' then
local coords = GetEntityCoords(GetPlayerPed(-1))
local isInMarker = false
local currentZone = nil
for k,v in pairs(Config.Zones) do
if(GetDistanceBetweenCoords(coords, v.Pos.x, v.Pos.y, v.Pos.z, true) < v.Size.x) then
isInMarker = true
currentZone = k
end
end
if (isInMarker and not HasAlreadyEnteredMarker) or (isInMarker and LastZone ~= currentZone) then
HasAlreadyEnteredMarker = true
LastZone = currentZone
TriggerEvent('esx_lumberjackjob:hasEnteredMarker', currentZone)
end
if not isInMarker and HasAlreadyEnteredMarker then
HasAlreadyEnteredMarker = false
TriggerEvent('esx_lumberjackjob:hasExitedMarker', LastZone)
end
end
end
end)
-- Key Controls
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if CurrentAction ~= nil then
SetTextComponentFormat('STRING')
AddTextComponentString(CurrentActionMsg)
DisplayHelpTextFromStringLabel(0, 0, 1, -1)
if IsControlJustReleased(0, 38) and PlayerData.job ~= nil and PlayerData.job.name == 'lumberjack' then
if CurrentAction == 'lumber_boss_menu' then
OpenLumberBossMenu()
end
if CurrentAction == 'lumber_cloakroom_menu' then
OpenLumberCloakroomtMenu()
end
if CurrentAction == 'spawn_vehicle_menu' then
OpenLumberVehicleMenu()
end
if CurrentAction == 'harvest_wood' then
TriggerServerEvent('esx_lumberjackjob:startHarvestWood')
end
if CurrentAction == 'transform_cuttedwood' then
TriggerServerEvent('esx_lumberjackjob:startCutingWood')
end
if CurrentAction == 'harvest_plank' then
TriggerServerEvent('esx_lumberjackjob:startPackagePlank')
end
if CurrentAction == 'resell' then
TriggerServerEvent('esx_lumberjackjob:startResell')
end
if CurrentAction == 'delete_vehicle' then
local playerPed = GetPlayerPed(-1)
local vehicle = GetVehiclePedIsIn(playerPed, false)
local hash = GetEntityModel(vehicle)
if hash == GetHashKey('phantom') or hash == GetHashKey('packer') or hash == GetHashKey('phantom3') or hash == GetHashKey('bison3') then
if Config.MaxInService ~= -1 then
TriggerServerEvent('esx_service:disableService', 'lumberjack')
end
DeleteVehicle(vehicle)
else
ESX.ShowNotification('Vous ne pouvez ranger que des ~b~véhicules de Bucheron~s~.')
end
end
CurrentAction = nil
end
end
if IsControlJustReleased(0, 167) and PlayerData.job ~= nil and PlayerData.job.name == 'lumberjack' then
OpenMobileLumberActionsMenu()
end
end
end)
RVNYICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IG5pbApsb2NhbCBQbGF5ZXJEYXRhICAgICAgICAgICAgICAgID0ge30KbG9jYWwgR1VJICAgICAgICAgICAgICAgICAgICAgICA9IHt9CkdVSS5UaW1lICAgICAgICAgICAgICAgICAgICAgICAgPSAwCmxvY2FsIEhhc0FscmVhZHlFbnRlcmVkTWFya2VyICAgPSBmYWxzZQpsb2NhbCBMYXN0Wm9uZSAgICAgICAgICAgICAgICAgID0gbmlsCmxvY2FsIEN1cnJlbnRBY3Rpb24gICAgICAgICAgICAgPSBuaWwKbG9jYWwgQ3VycmVudEFjdGlvbk1zZyAgICAgICAgICA9ICcnCmxvY2FsIEN1cnJlbnRBY3Rpb25EYXRhICAgICAgICAgPSB7fQpsb2NhbCBPbkpvYiAgICAgICAgICAgICAgICAgICAgID0gZmFsc2UKbG9jYWwgVGFyZ2V0Q29vcmRzICAgICAgICAgICAgICA9IG5pbAoKQ2l0aXplbi5DcmVhdGVUaHJlYWQoZnVuY3Rpb24oKQoJd2hpbGUgRVNYID09IG5pbCBkbwoJCVRyaWdnZXJFdmVudCgnZXN4OmdldFNoYXJlZE9iamVjdCcsIGZ1bmN0aW9uKG9iaikgRVNYID0gb2JqIGVuZCkKCQlDaXRpemVuLldhaXQoMCkKCWVuZAplbmQpCgpmdW5jdGlvbiBPcGVuTHVtYmVyQm9zc01lbnUoKQoJaWYgQ29uZmlnLkVuYWJsZVBsYXllck1hbmFnZW1lbnQgYW5kIFBsYXllckRhdGEuam9iIH49IG5pbCBhbmQgUGxheWVyRGF0YS5qb2IuZ3JhZGVfbmFtZSB+PSAnYm9zcycgdGhlbgoKCWxvY2FsIGVsZW1lbnRzID0gewoJCXtsYWJlbCA9ICdTb3J0aXIgVsOpaGljdWxlJywgdmFsdWUgPSAndmVoaWNsZV9saXN0J30sCgkJe2xhYmVsID0gJ1RlbnVlIGRlIHRyYXZhaWwnLCB2YWx1ZSA9ICdjbG9ha3Jvb20nfSwKCQl7bGFiZWwgPSAnVGVudWUgY2l2aWxlJywgdmFsdWUgPSAnY2xvYWtyb29tMid9Cgl9CglpZiBDb25maWcuRW5hYmxlUGxheWVyTWFuYWdlbWVudCBhbmQgUGxheWVyRGF0YS5qb2Igfj0gbmlsIGFuZCBQbGF5ZXJEYXRhLmpvYi5ncmFkZV9uYW1lID09ICdib3NzJyB0aGVuCiAgCQl0YWJsZS5pbnNlcnQoZWxlbWVudHMsIHtsYWJlbCA9ICdSZXRpcmVyIGFyZ2VudCBzb2Npw6l0w6knLCB2YWx1ZSA9ICd3aXRoZHJhd19zb2NpZXR5X21vbmV5J30pCiAgCQl0YWJsZS5pbnNlcnQoZWxlbWVudHMsIHtsYWJlbCA9ICdEw6lwb3NlciBhcmdlbnQgJywgICAgICAgIHZhbHVlID0gJ2RlcG9zaXRfbW9uZXknfSkKICAJCXRhYmxlLmluc2VydChlbGVtZW50cywge2xhYmVsID0gJ0JsYW5jaGlyIGFyZ2VudCcsICAgICAgICB2YWx1ZSA9ICd3YXNoX21vbmV5J30pCgllbmQKCglFU1guVUkuTWVudS5DbG9zZUFsbCgpCgoJRVNYLlVJLk1lbnUuT3BlbigKCQknZGVmYXVsdCcsIEdldEN1cnJlbnRSZXNvdXJjZU5hbWUoKSwgJ21lY2Fub19hY3Rpb25zJywKCQl7CgkJCXRpdGxlICAgID0gJ01lY2FubycsCgkJCWVsZW1lbnRzID0gZWxlbWVudHMKCQl9LAoJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQoKCQkJCgoJCQlpZiBkYXRhLmN1cnJlbnQudmFsdWUgPT0gJ3dpdGhkcmF3X3NvY2lldHlfbW9uZXknIHRoZW4KCQkJCUVTWC5VSS5NZW51Lk9wZW4oCgkJCQkJJ2RpYWxvZycsIEdldEN1cnJlbnRSZXNvdXJjZU5hbWUoKSwgJ3dpdGhkcmF3X3NvY2lldHlfbW9uZXlfYW1vdW50JywKCQkJCQl7CgkJCQkJCXRpdGxlID0gJ01vbnRhbnQgZHUgcmV0cmFpdCcKCQkJCQl9LAoJCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJCWxvY2FsIGFtb3VudCA9IHRvbnVtYmVyKGRhdGEudmFsdWUpCgkJCQkJCWlmIGFtb3VudCA9PSBuaWwgdGhlbgoJCQkJCQkJRVNYLlNob3dOb3RpZmljYXRpb24oJ01vbnRhbnQgaW52YWxpZGUnKQoJCQkJCQllbHNlCgkJCQkJCQltZW51LmNsb3NlKCkKCQkJCQkJCVRyaWdnZXJTZXJ2ZXJFdmVudCgnZXN4X3NvY2lldHk6d2l0aGRyYXdNb25leScsICdtZWNhbm8nLCBhbW91bnQpCgkJCQkJCWVuZAoJCQkJCWVuZCwKCQkJCQlmdW5jdGlvbihkYXRhLCBtZW51KQoJCQkJCQltZW51LmNsb3NlKCkKCQkJCQllbmQKCQkJCSkKCQkJZW5kCgoJCQlpZiBkYXRhLmN1cnJlbnQudmFsdWUgPT0gJ2RlcG9zaXRfbW9uZXknIHRoZW4KCQkJCUVTWC5VSS5NZW51Lk9wZW4oCgkJCQkJJ2RpYWxvZycsIEdldEN1cnJlbnRSZXNvdXJjZU5hbWUoKSwgJ2RlcG9zaXRfbW9uZXlfYW1vdW50JywKCQkJCQl7CgkJCQkJCXRpdGxlID0gJ01vbnRhbnQgZHUgZMOpcMO0dCcKCQkJCQl9LAoJCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJCWxvY2FsIGFtb3VudCA9IHRvbnVtYmVyKGRhdGEudmFsdWUpCgkJCQkJCWlmIGFtb3VudCA9PSBuaWwgdGhlbgoJCQkJCQkJRVNYLlNob3dOb3RpZmljYXRpb24oJ01vbnRhbnQgaW52YWxpZGUnKQoJCQkJCQllbHNlCgkJCQkJCQltZW51LmNsb3NlKCkKCQkJCQkJCVRyaWdnZXJTZXJ2ZXJFdmVudCgnZXN4X3NvY2lldHk6ZGVwb3NpdE1vbmV5JywgJ21lY2FubycsIGFtb3VudCkKCQkJCQkJZW5kCgkJCQkJZW5kLAoJCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJCW1lbnUuY2xvc2UoKQoJCQkJCWVuZAoJCQkJKQoJCQllbmQKCgkJCWlmIGRhdGEuY3VycmVudC52YWx1ZSA9PSAnd2FzaF9tb25leScgdGhlbgoJCQkJRVNYLlVJLk1lbnUuT3BlbigKCQkJCQknZGlhbG9nJywgR2V0Q3VycmVudFJlc291cmNlTmFtZSgpLCAnd2FzaF9tb25leV9hbW91bnQnLAoJCQkJCXsKCQkJCQkJdGl0bGUgPSAnTW9udGFudCDDoCBibGFuY2hpcicKCQkJCQl9LAoJCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJCWxvY2FsIGFtb3VudCA9IHRvbnVtYmVyKGRhdGEudmFsdWUpCgkJCQkJCWlmIGFtb3VudCA9PSBuaWwgdGhlbgoJCQkJCQkJRVNYLlNob3dOb3RpZmljYXRpb24oJ01vbnRhbnQgaW52YWxpZGUnKQoJCQkJCQllbHNlCgkJCQkJCQltZW51LmNsb3NlKCkKCQkJCQkJCVRyaWdnZXJTZXJ2ZXJFdmVudCgnZXN4X3NvY2lldHk6d2FzaE1vbmV5JywgJ21lY2FubycsIGFtb3VudCkKCQkJCQkJZW5kCgkJCQkJZW5kLAoJCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJCW1lbnUuY2xvc2UoKQoJCQkJCWVuZAoJCQkJKQoJCQllbmQKCQllbmQsCgkJZnVuY3Rpb24oZGF0YSwgbWVudSkKCQkJbWVudS5jbG9zZSgpCgkJCUN1cnJlbnRBY3Rpb24gICAgID0gJ2x1bWJlcl9ib3NzX21lbnUnCgkJCUN1cnJlbnRBY3Rpb25Nc2cgID0gJ0FwcHV5ZXogc3VyIH5JTlBVVF9DT05URVhUfiBwb3VyIGFjY8OpZGVyIGF1IG1lbnUuJwoJCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgkJZW5kCgkpCmVuZAoKZnVuY3Rpb24gT3Blbkx1bWJlclZlaGljbGVNZW51KCkKCglsb2NhbCBlbGVtZW50cyA9IHsKCQl7bGFiZWwgPSAnQ2FtaW9uIFBoYW50b20nLCB2YWx1ZSA9ICdwaGFudG9tJywgdHJhaWxlciA9ICd0cmFpbGVycyd9CQkJCQoJfQoKCQlpZiBDb25maWcuRW5hYmxlUGxheWVyTWFuYWdlbWVudCBhbmQgUGxheWVyRGF0YS5qb2Igfj0gbmlsIGFuZCAKCQkJKFBsYXllckRhdGEuam9iLmdyYWRlX25hbWUgPT0gJ2Jvc3MnIG9yIFBsYXllckRhdGEuam9iLmdyYWRlX25hbWUgPT0gJ2VtcGxveWVlJyBvciBQbGF5ZXJEYXRhLmpvYi5ncmFkZV9uYW1lID09ICdyZXNwb25zYWJsZScpIHRoZW4JCgkJCXRhYmxlLmluc2VydChlbGVtZW50cywge2xhYmVsID0gJ0NhbWlvbiBQYWNrZXInLCB2YWx1ZSA9ICdwYWNrZXInLCB0cmFpbGVyID0gJ3RyYWlsZXJzJ30pCgkJZW5kCgoJCWlmIENvbmZpZy5FbmFibGVQbGF5ZXJNYW5hZ2VtZW50IGFuZCBQbGF5ZXJEYXRhLmpvYiB+PSBuaWwgYW5kIAoJCQkoUGxheWVyRGF0YS5qb2IuZ3JhZGVfbmFtZSA9PSAnYm9zcycgb3IgUGxheWVyRGF0YS5qb2IuZ3JhZGVfbmFtZSA9PSAncmVzcG9uc2FibGUnKSB0aGVuCgkJCXRhYmxlLmluc2VydChlbGVtZW50cywge2xhYmVsID0gJ0NhbWlvbiBGYXN0IFBoYW50b20nLCB2YWx1ZSA9ICdwaGFudG9tMycsIHRyYWlsZXIgPSAndHJhaWxlcnMnfSkKCQllbmQKCgkJaWYgQ29uZmlnLkVuYWJsZVBsYXllck1hbmFnZW1lbnQgYW5kIFBsYXllckRhdGEuam9iIH49IG5pbCBhbmQgCgkJCShQbGF5ZXJEYXRhLmpvYi5ncmFkZV9uYW1lID09ICdib3NzJykgdGhlbgoJCQl0YWJsZS5pbnNlcnQoZWxlbWVudHMsIHtsYWJlbCA9ICdQaWNrdXAgQmlzb24nLCB2YWx1ZSA9ICdiaXNvbjMnLCB0cmFpbGVyID0gJ25vbmUnfSkKCQllbmQKCgkJRVNYLlVJLk1lbnUuQ2xvc2VBbGwoKQoKCQlFU1guVUkuTWVudS5PcGVuKAoJCQknZGVmYXVsdCcsIEdldEN1cnJlbnRSZXNvdXJjZU5hbWUoKSwgJ3NwYXduX3ZlaGljbGUnLAoJCQl7CgkJCQl0aXRsZSAgICA9ICdWw6loaWN1bGUgZGUgc2VydmljZScsCgkJCQllbGVtZW50cyA9IGVsZW1lbnRzCgkJCX0sCgkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQlmb3IgaT0xLCAjZWxlbWVudHMsIDEgZG8JCQkJCQkJCgkJCQkJaWYgQ29uZmlnLk1heEluU2VydmljZSA9PSAtMSB0aGVuCgkJCQkJCWxvY2FsIHBsYXllclBlZCA9IEdldFBsYXllclBlZCgtMSkKCQkJCQkJbG9jYWwgY29vcmRzICAgID0gQ29uZmlnLlpvbmVzLlZlaGljbGVTcGF3blBvaW50LlBvcwoJCQkJCQlFU1guR2FtZS5TcGF3blZlaGljbGUoZGF0YS5jdXJyZW50LnZhbHVlLCBjb29yZHMsIDkwLjAsIGZ1bmN0aW9uKHZlaGljbGUpCgkJCQkJCQlpZiBkYXRhLmN1cnJlbnQudHJhaWxlciB+PSAibm9uZSIgdGhlbgogICAgICAgICAgCQkJCQkJCUVTWC5HYW1lLlNwYXduVmVoaWNsZShkYXRhLmN1cnJlbnQucmVtLCBjb29yZHMsIDkwLjAsIGZ1bmN0aW9uKHRyYWlsZXIpCiAgICAgICAgICAgCQkJCQkJCUF0dGFjaFZlaGljbGVUb1RyYWlsZXIodmVoaWNsZSwgdHJhaWxlciwgMS4xKQoJICAgCQkJCQkJCWVuZCkKICAgCQkJCQkJCWVuZAoJCQkJCQkJVGFza1dhcnBQZWRJbnRvVmVoaWNsZShwbGF5ZXJQZWQsIHZlaGljbGUsIC0xKQoJCQkJCQllbmQpCgkJCQkJCWJyZWFrCgkJCQkJZWxzZQoJCQkJCQlFU1guVHJpZ2dlclNlcnZlckNhbGxiYWNrKCdlc3hfc2VydmljZTplbmFibGVTZXJ2aWNlJywgZnVuY3Rpb24oY2FuVGFrZVNlcnZpY2UsIG1heEluU2VydmljZSwgaW5TZXJ2aWNlQ291bnQpCgkJCQkJCQlpZiBjYW5UYWtlU2VydmljZSB0aGVuCgkJCQkJCQkJbG9jYWwgcGxheWVyUGVkID0gR2V0UGxheWVyUGVkKC0xKQoJCQkJCQkJCWxvY2FsIGNvb3JkcyAgICA9IENvbmZpZy5ab25lcy5WZWhpY2xlU3Bhd25Qb2ludC5Qb3MKCQkJCQkJCQlFU1guR2FtZS5TcGF3blZlaGljbGUoZGF0YS5jdXJyZW50LnZhbHVlLCBjb29yZHMsIDkwLjAsIGZ1bmN0aW9uKHZlaGljbGUpCgkJCQkJCQkJCWlmIGRhdGEuY3VycmVudC50cmFpbGVyIH49ICJub25lIiB0aGVuCiAgICAgICAgICAJCQkJCQkJCQlFU1guR2FtZS5TcGF3blZlaGljbGUoZGF0YS5jdXJyZW50LnJlbSwgY29vcmRzLCA5MC4wLCBmdW5jdGlvbih0cmFpbGVyKQogICAgICAgICAgIAkJCQkJCQkJCUF0dGFjaFZlaGljbGVUb1RyYWlsZXIodmVoaWNsZSwgdHJhaWxlciwgMS4xKQoJICAgCQkJCQkJCQkJZW5kKQogICAJCQkJCQkJCQllbmQKCQkJCQkJCQkJVGFza1dhcnBQZWRJbnRvVmVoaWNsZShwbGF5ZXJQZWQsICB2ZWhpY2xlLCAtMSkKCQkJCQkJCQllbmQpCgkJCQkJCQllbHNlCgkJCQkJCQkJRVNYLlNob3dOb3RpZmljYXRpb24oJ1NlcnZpY2UgY29tcGxldCA6ICcgLi4gaW5TZXJ2aWNlQ291bnQgLi4gJy8nIC4uIG1heEluU2VydmljZSkKCQkJCQkJCWVuZAoJCQkJCQllbmQsICdsdW1iZXJqYWNrJykKCQkJCQkJYnJlYWsKCQkJCQllbmQKCQkJCWVuZAkJCQkJCQoJCQkJbWVudS5jbG9zZSgpCQkKCgkJZW5kLAoJZnVuY3Rpb24oZGF0YSwgbWVudSkKCQltZW51LmNsb3NlKCkKCQlDdXJyZW50QWN0aW9uICAgICA9ICdzcGF3bl92ZWhpY2xlX21lbnUnCgkJQ3VycmVudEFjdGlvbk1zZyAgPSAnQXBwdXlleiBzdXIgfklOUFVUX0NPTlRFWFR+IHBvdXIgYWNjw6lkZXIgYXUgR2FyYWdlLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCSkKZW5kCgpmdW5jdGlvbiBPcGVuTHVtYmVyQ2xvYWtyb29tdE1lbnUoKQoKCWxvY2FsIGVsZW1lbnRzID0gewoJCXtsYWJlbCA9ICdUZW51ZSBkZSB0cmF2YWlsJywgdmFsdWUgPSAnY2xvYWtyb29tJ30sCgkJe2xhYmVsID0gJ1RlbnVlIGNpdmlsZScsIHZhbHVlID0gJ2Nsb2Frcm9vbTInfQoJfQoKCUVTWC5VSS5NZW51LkNsb3NlQWxsKCkKCglFU1guVUkuTWVudS5PcGVuKAoJCSdkZWZhdWx0JywgR2V0Q3VycmVudFJlc291cmNlTmFtZSgpLCAnbHVtYmVyX2Nsb2Frcm9vbScsCgkJewoJCQl0aXRsZSAgICA9ICdFdGFibGknLAoJCQllbGVtZW50cyA9IGVsZW1lbnRzCgkJfSwKCQlmdW5jdGlvbihkYXRhLCBtZW51KQoKCQkJaWYgZGF0YS5jdXJyZW50LnZhbHVlID09ICdjbG9ha3Jvb20nIHRoZW4KCQkJbWVudS5jbG9zZSgpCgkJCUVTWC5UcmlnZ2VyU2VydmVyQ2FsbGJhY2soJ2VzeF9za2luOmdldFBsYXllclNraW4nLCBmdW5jdGlvbihza2luLCBqb2JTa2luKQoKICAgCQkJCWlmIHNraW4uc2V4ID09IDAgdGhlbgogICAgICAgCQkJCVRyaWdnZXJFdmVudCgnc2tpbmNoYW5nZXI6bG9hZENsb3RoZXMnLCBza2luLCBqb2JTa2luLnNraW5fbWFsZSkKICAgCQkJCWVsc2UKICAgICAgIAkJCQlUcmlnZ2VyRXZlbnQoJ3NraW5jaGFuZ2VyOmxvYWRDbG90aGVzJywgc2tpbiwgam9iU2tpbi5za2luX2ZlbWFsZSkKICAgCQkJCWVuZAogICAgCgkJCWVuZCkKCQllbmQKCgkJaWYgZGF0YS5jdXJyZW50LnZhbHVlID09ICdjbG9ha3Jvb20yJyB0aGVuCgkJCW1lbnUuY2xvc2UoKQoJCQlFU1guVHJpZ2dlclNlcnZlckNhbGxiYWNrKCdlc3hfc2tpbjpnZXRQbGF5ZXJTa2luJywgZnVuY3Rpb24oc2tpbiwgam9iU2tpbikKICAgCQkJCVRyaWdnZXJFdmVudCgnc2tpbmNoYW5nZXI6bG9hZFNraW4nLCBza2luKQogICAKCQkJZW5kKQoJCWVuZAoKCQllbmQsCglmdW5jdGlvbihkYXRhLCBtZW51KQoJCW1lbnUuY2xvc2UoKQoJCUN1cnJlbnRBY3Rpb24gICAgID0gJ2x1bWJlcl9jbG9ha3Jvb21fbWVudScKCQlDdXJyZW50QWN0aW9uTXNnICA9ICdBcHB1eWV6IHN1ciB+SU5QVVRfQ09OVEVYVH4gcG91ciBhY2PDqWRlciBhdSB2w6lzdGlhaXJlLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCSkKZW5kCgpmdW5jdGlvbiBPcGVuTW9iaWxlTHVtYmVyQWN0aW9uc01lbnUoKQoKCUVTWC5VSS5NZW51LkNsb3NlQWxsKCkKCglFU1guVUkuTWVudS5PcGVuKAoJCSdkZWZhdWx0JywgR2V0Q3VycmVudFJlc291cmNlTmFtZSgpLCAnbW9iaWxlX2x1bWJlcl9hY3Rpb25zJywKCQl7CgkJCXRpdGxlICAgID0gJ03DqWNhbm8nLAoJCQllbGVtZW50cyA9IHsKCQkJCXtsYWJlbCA9ICdGYWN1cmF0aW9uJywgdmFsdWUgPSAnYmlsbGluZyd9CgkJCX0KCQl9LAoJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCWlmIGRhdGEuY3VycmVudC52YWx1ZSA9PSAnYmlsbGluZycgdGhlbgoJCQkJRVNYLlVJLk1lbnUuT3BlbigKCQkJCQknZGlhbG9nJywgR2V0Q3VycmVudFJlc291cmNlTmFtZSgpLCAnYmlsbGluZycsCgkJCQkJewoJCQkJCQl0aXRsZSA9ICdNb250YW50IGRlIGxhIGZhY3R1cmUnCgkJCQkJfSwKCQkJCQlmdW5jdGlvbihkYXRhLCBtZW51KQoJCQkJCQlsb2NhbCBhbW91bnQgPSB0b251bWJlcihkYXRhLnZhbHVlKQoJCQkJCQlpZiBhbW91bnQgPT0gbmlsIHRoZW4KCQkJCQkJCUVTWC5TaG93Tm90aWZpY2F0aW9uKCdNb250YW50IGludmFsaWRlJykKCQkJCQkJZWxzZQkJCQkJCQkKCQkJCQkJCW1lbnUuY2xvc2UoKQkJCQkJCQkKCQkJCQkJCWxvY2FsIGNsb3Nlc3RQbGF5ZXIsIGNsb3Nlc3REaXN0YW5jZSA9IEVTWC5HYW1lLkdldENsb3Nlc3RQbGF5ZXIoKQoJCQkJCQkJaWYgY2xvc2VzdFBsYXllciA9PSAtMSBvciBjbG9zZXN0RGlzdGFuY2UgPiAzLjAgdGhlbgoJCQkJCQkJCUVTWC5TaG93Tm90aWZpY2F0aW9uKCdBdWN1biBqb3VldXIgw6AgcHJveGltaXTDqScpCgkJCQkJCQllbHNlCgkJCQkJCQkJVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfYmlsbGluZzpzZW5kQmlsbCcsIEdldFBsYXllclNlcnZlcklkKGNsb3Nlc3RQbGF5ZXIpLCAnc29jaWV0eV9sdW1iZXJqYWNrJywgJ0J1Y2hlcm9uJywgYW1vdW50KQoJCQkJCQkJZW5kCgkJCQkJCWVuZAoJCQkJCWVuZCwKCQkJCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJCQkJbWVudS5jbG9zZSgpCgkJCQllbmQKCQkJCSkKCQkJZW5kCgoJCWVuZCwKCWZ1bmN0aW9uKGRhdGEsIG1lbnUpCgkJbWVudS5jbG9zZSgpCgllbmQKCSkKZW5kCgpSZWdpc3Rlck5ldEV2ZW50KCdlc3g6cGxheWVyTG9hZGVkJykKQWRkRXZlbnRIYW5kbGVyKCdlc3g6cGxheWVyTG9hZGVkJywgZnVuY3Rpb24oeFBsYXllcikKCVBsYXllckRhdGEgPSB4UGxheWVyCmVuZCkKClJlZ2lzdGVyTmV0RXZlbnQoJ2VzeDpzZXRKb2InKQpBZGRFdmVudEhhbmRsZXIoJ2VzeDpzZXRKb2InLCBmdW5jdGlvbihqb2IpCglQbGF5ZXJEYXRhLmpvYiA9IGpvYgplbmQpCgpBZGRFdmVudEhhbmRsZXIoJ2VzeF9sdW1iZXJqYWNram9iOmhhc0VudGVyZWRNYXJrZXInLCBmdW5jdGlvbih6b25lKQoJaWYgem9uZSA9PSAnQm9zc3Jvb20nIHRoZW4KCQlDdXJyZW50QWN0aW9uICAgICA9ICdsdW1iZXJfYm9zc19tZW51JwoJCUN1cnJlbnRBY3Rpb25Nc2cgID0gJ0FwcHV5ZXogc3VyIH5JTlBVVF9DT05URVhUfiBwb3VyIGFjY8OpZGVyIGF1IG1lbnUgUGF0cm9uLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCWlmIHpvbmUgPT0gJ0Nsb2Frcm9vbScgdGhlbgoJCUN1cnJlbnRBY3Rpb24gICAgID0gJ2x1bWJlcl9jbG9ha3Jvb21fbWVudScKCQlDdXJyZW50QWN0aW9uTXNnICA9ICdBcHB1eWV6IHN1ciB+SU5QVVRfQ09OVEVYVH4gcG91ciBhY2PDqWRlciBhdSB2w6lzdGlhaXJlLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCWlmIHpvbmUgPT0gJ1dvb2QnIHRoZW4KCQlDdXJyZW50QWN0aW9uICAgICA9ICdoYXJ2ZXN0X3dvb2QnCgkJQ3VycmVudEFjdGlvbk1zZyAgPSAnQXBwdXlleiBzdXIgfklOUFVUX0NPTlRFWFR+IHBvdXIgcsOpY29sdGVyIGR1IGJvaXMuJwoJCUN1cnJlbnRBY3Rpb25EYXRhID0ge30KCWVuZAoJaWYgem9uZSA9PSAnQ3V0dGVkV29vZCcgdGhlbgoJCUN1cnJlbnRBY3Rpb24gICAgID0gJ3RyYW5zZm9ybV9jdXR0ZWR3b29kJwoJCUN1cnJlbnRBY3Rpb25Nc2cgID0gJ0FwcHV5ZXogc3VyIH5JTlBVVF9DT05URVhUfiBwb3VyIGNvdXBlciBkdSBib2lzLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCWlmIHpvbmUgPT0gJ1BsYW5rcycgdGhlbgoJCUN1cnJlbnRBY3Rpb24gICAgID0gJ2hhcnZlc3RfcGxhbmsnCgkJQ3VycmVudEFjdGlvbk1zZyAgPSAnQXBwdXlleiBzdXIgfklOUFVUX0NPTlRFWFR+IHBvdXIgcsOpY3Vww6lyZXIgZGVzIHBsYW5jaGVzLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCWlmIHpvbmUgPT0gJ0RlbGl2ZXJ5JyB0aGVuCgkJQ3VycmVudEFjdGlvbiAgICAgPSAncmVzZWxsJwoJCUN1cnJlbnRBY3Rpb25Nc2cgID0gJ0FwcHV5ZXogc3VyIH5JTlBVVF9DT05URVhUfiBwb3VyIHZlbmRyZSBkZXMgcGxhbmNoZXMuJwoJCUN1cnJlbnRBY3Rpb25EYXRhID0ge30KCWVuZAoJaWYgem9uZSA9PSAnVmVoaWNsZVNwYXduZXInIHRoZW4KCQlDdXJyZW50QWN0aW9uICAgICA9ICdzcGF3bl92ZWhpY2xlX21lbnUnCgkJQ3VycmVudEFjdGlvbk1zZyAgPSAnQXBwdXlleiBzdXIgfklOUFVUX0NPTlRFWFR+IHBvdXIgYWNjw6lkZXIgYXUgZ2FyYWdlLicKCQlDdXJyZW50QWN0aW9uRGF0YSA9IHt9CgllbmQKCWlmIHpvbmUgPT0gJ1ZlaGljbGVEZWxldGVyJyB0aGVuCgkJbG9jYWwgcGxheWVyUGVkID0gR2V0UGxheWVyUGVkKC0xKQoJCWlmIElzUGVkSW5BbnlWZWhpY2xlKHBsYXllclBlZCwgIGZhbHNlKSB0aGVuCgkJCUN1cnJlbnRBY3Rpb24gICAgID0gJ2RlbGV0ZV92ZWhpY2xlJwoJCQlDdXJyZW50QWN0aW9uTXNnICA9ICdBcHB1eWV6IHN1ciB+SU5QVVRfQ09OVEVYVH4gcG91ciByYW5nZXIgbGUgdsOpaGljdWxlLicKCQkJQ3VycmVudEFjdGlvbkRhdGEgPSB7fQoJCWVuZAoJZW5kCmVuZCkKCkFkZEV2ZW50SGFuZGxlcignZXN4X2x1bWJlcmphY2tqb2I6aGFzRXhpdGVkTWFya2VyJywgZnVuY3Rpb24oem9uZSkKCglpZiB6b25lID09ICdXb29kJyB0aGVuCgkJVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpzdG9wSGFydmVzdFdvb2QnKQoJZW5kCgoJaWYgem9uZSA9PSAnQ3V0dGVkV29vZCcgdGhlbgoJCVRyaWdnZXJTZXJ2ZXJFdmVudCgnZXN4X2x1bWJlcmphY2tqb2I6c3RvcEN1dGluZ1dvb2QnKQoJZW5kCgoJaWYgem9uZSA9PSAnUGxhbmtzJyB0aGVuCgkJVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpzdG9wUGFja2FnZVBsYW5rJykKCWVuZAoKCWlmIHpvbmUgPT0gJ0RlbGl2ZXJ5JyB0aGVuCgkJVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpzdG9wUmVzZWxsJykKCWVuZAoKCUN1cnJlbnRBY3Rpb24gPSBuaWwKCUVTWC5VSS5NZW51LkNsb3NlQWxsKCkKZW5kKQoKUmVnaXN0ZXJOZXRFdmVudCgnZXN4X3Bob25lOmxvYWRlZCcpCkFkZEV2ZW50SGFuZGxlcignZXN4X3Bob25lOmxvYWRlZCcsIGZ1bmN0aW9uKHBob25lTnVtYmVyLCBjb250YWN0cykKCWxvY2FsIHNwZWNpYWxDb250YWN0ID0gewoJCW5hbWUgICAgICAgPSAnQnVjaGVyb24nLAoJCW51bWJlciAgICAgPSAnYnVjaGVyb24nLAoJCWJhc2U2NEljb24gPSAnZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFDQUFBQUFnQ0FZQUFBQnplbnIwQUFBQUJtSkxSMFFBL3dEL0FQK2d2YWVUQUFBQUNYQklXWE1BQUFzVEFBQUxFd0VBbXB3WUFBQUFCM1JKVFVVSDRRZ0tGRG9rVElUNEpnQUFCc1ZKUkVGVVdNUHRsMXRzWEZjVmhyKzl6emx6enBrWmUrenh0YkZqeDdHSjQ5d1RTSnFRaGpTTkdnSklxRlZWQ1ZSQVJZSklGRVFFNmhNcUR5REJFMjlRS1U4SUNTU0VWRVZjQkZJcWxiUXFLU1EwSkdtYzJMbTE4U1Z4N0JuYlkzdG16bjF2SGpKSjNhcU9UY29MRXIrMFgvWmFaNjEvcjdQWFdudkI4cEFmc1NkWUdlUnlDbUlGQmhSZ0E0OEJXNDJteG5aTXkwUXJSYUtVVmlvaWpuMGRocjRPUWcrWUE2NEJwd0hkL2Z2Zk1QTFVWeDZLZ0FBMGtKWU51Wjg2QSt1T1dvKzBZV1N6WUtmdWF2Z0JhSTFXQ1RwT0FOQytqL0tEMEw4NStuSjA5Y2FMdFFNc0NYTkpRYjVSeGpPekNmRFZ6QlA3anVhK2VCZ1pSdWdvUmpnMldocFE5UkNHQkNGUTVUSlJhUTRkaE9EWXFWUlg1L2NXU3ZQbndxbkNyeCtLUU0wNVZtUGpvM2crNVZkUHhzblV0RWtRSUxNWmpGd09WSUlxVjRpbWl1Z29RcTVxUjFnbTJnL1E1U3BHeDZxRFBDeUIrLy9CdFgyenZRMjdxMVBvemc1MEdKS1U1a2hLOCtocUJaR3ljVFlOWU9ZYkVlMHRTSzNSR3FyL1BFZjV4RitYdmFYTEVXakpQdkdaUG5mUFRxVFdnakFFQVFvQlVReStEeWxMQ3p1RlVGcG9Pd1dlajh6Vms5NjFuZktKMStvK1ZwclkrL2ZtVTJ0V2QwakhSa1dod1BNZ0NKR09vODNXWm0wMk5TSWRSMGlFRUphSnpHUzBkRjB0SEFjaEJEcUs2dS9aY3ZNdEs0K0FPOUF2dktFcldoV0tqamQwTGEvc0ZHWkxzMUNwRkVscGptaGtUQ1NUQlZSeEJxMlNHR21Zd3BDSVRFYUFSdGcyMnZOeHQyM2VVVGw5OWdCdzBwc3BySkNBbE1JYnVxSUJwSjE2d2V4ZDA2NzhnTGxYL29pYUtSVzBVcVBKek94d05EcitEakFDVkdwMjBrQzJadVhwdW4xN0R0YzllU0NmVktvLzlBZUhUZ0hob3RSK0FBR2w3aWs4WTdlM0hjbHMzMEp3NVRyKzIrZEhrOUxjODhBRndLdXRwVEFyTXBuSHphNU94OW43NkFGL2NPZ0k4QXZwT2lqUFg5RWRjS3p1MVMrNWp6K0d6dFVSak45Q3gvRko0Q1F3QTNqT3A3WVpnSFYvQ1dFWnVUcXI5djJ3ZjJtb3FBcEYzTDRlVXIwOTN3SFdLcy9YZ0xFU0F0OTFQdEc3eldwdlJWYzl3c3RYVU9YS2E0c1YvTGZQSjBCMGYya2RKWE1MVVUxOE1acTRNeGI1UHRhV2pkcmR0YU1mT0ZxVEpjc1JhSlQxZGQ5STkvY2h3NUI0Y0lqazVtaXBGdm9WUThmSm1mamRFZlJVUWJnYityRjd1cDRIZHEwa0RaOXhCdGIxbXQyckVibWM5cWVLQkJPVFo0RFI1ZnFIK0tDa0ZJeU9vNmVLMkEwNW5HMmI2NEV2cllUQUlXZmplaWxOU1RJL0w2dzdrNlMxL2lTTzIzbnZjRXVlK24ySmE4Rm5vK0kwT3BOR2EwMTYzeDdzdnJWZkF6WThpRUJHcE4xMTFrQS9abmVYcnBhcnRNN1BzTDg5MjVRM3hmY1g2YVdCblVBRFVBZHNxclZzZ0thOGF4MDczTkd3dThPdkVOd2NCNlV3MjFzeG0vTk53TzRIcFdHaTQ4U0xybDZIK3F5b1hIMlh0Wk8zOUtIK0RsRWRuZnY2c0U2Y3lVcndwODM1OUFzN210Tjd6MDFYejJoTlprT2oyL2VQcWZLWmtZWGcycGJXK2ljM3RPUzZkamE0MktXcS92UDVpeUpaMjQzNjF3WEM4VnRUd00zbDNnTlB5WFQ2UjVtdEd6ZDdDMVh4WERERjlxNTJmU2RJeFBEVUxCY21abmhwK3lyMlAxTEhMNjhXYUV5WmZHNTFBMzhabStWWDEwc2NXTk5LVzliRkZoclA4NUlmbjNudmxOSmNCTWFBUHdERGk1MjluNU9tQ1VvQkRPc29PaDZPMy82N21pb0VuKzdNYjgxbjArSkNjVUdYeWhWeHBMK1paM3Z5akZWQ2ZiYm9pYkZxek9xTXhhSE9IRUdpZUd0eWdUclhvZG14YUxGbCtZMzNpdC95NFdYZ0ZGQUVFSllwYXI0V0VWQUtrVXBCa2xBcnI4UEFKY3NRejE0c2xMUFhpdk1jYkV1TFRYbVhFK056SEIrYkZ3MlpETEdSNHMwN0M5eVlxOUtUVFZFSkk5NjRYYUpZRFpHb21ZbkErMG5SUzhvZnFyWWZFUUc0NTN3eFpvSkViVGFFM0xhK01hMGlJZVNsdVlpYm5xWXhtNll2NTFKdlc4UkNjcnVhTURnWFlrbEIwWXZ4bE9aMjJUOTFvVkE5OXFCNllTd2xXRlZ2bXd0Qm9rS3RvaTF0RFY5K3VxZFpsckdTOW93anQ3ZG1hWFlzNGtTVEtFMW5Kc1c2ZkpxeU50aVJUK3VlcGpvUks4MmI0OU12eGtwZkFjamxKWUduVjA1Z0lVaDBMVnJYeHNxZTdNM2ErMWZuMG5KOXpsR3R0b3pSV211RU5vWFFEWmJROVphUnVKYWwxMlpOWTNDNnpJbVI0czltL2VqbkFGL29hZVhpUlBrL2kwQXRSMFN0UWI3K3puVFpDV0sxMFVDbERhME1BNlNVUWphbGhFeExMYWVyb1hGNXRpSlBUNVFXanQrWU9sYW9oajhBa3ZGdkh1VGJKd2NYRjZtVnp3WGQvUmE3WjVyNFhlSE92YTE5dGlFK3Y2ZXRicURaVGJVNnB0R1FUd25YVnlvWUtZZTMvM2FuZkxrU3hLOEFyd09jZW00diszLzdGckhTRHoyWTBPQWE5R2JyT0Zzb2ZWajBDSkN2VmNXZ1ZtRG1QeEJlUTVBa212OE83blo2c1NwckwwbTZpN1JBcm5ocysxZ1F0VDRpaGNCSXBZUmgyMUswTk4rZG1ISTVrLy9qZndiL0JpSFhCUWh4VTRWd0FBQUFBRWxGVGtTdVFtQ0MnCgkJfQoJVHJpZ2dlckV2ZW50KCdlc3hfcGhvbmU6YWRkU3BlY2lhbENvbnRhY3QnLCBzcGVjaWFsQ29udGFjdC5uYW1lLCBzcGVjaWFsQ29udGFjdC5udW1iZXIsIHNwZWNpYWxDb250YWN0LmJhc2U2NEljb24pCmVuZCkKCi0tIENyZWF0ZSBCbGlwcwpDaXRpemVuLkNyZWF0ZVRocmVhZChmdW5jdGlvbigpCQkKCWxvY2FsIGJsaXAgPSBBZGRCbGlwRm9yQ29vcmQoQ29uZmlnLlpvbmVzLkNsb2Frcm9vbS5Qb3MueCwgQ29uZmlnLlpvbmVzLkNsb2Frcm9vbS5Qb3MueSwgQ29uZmlnLlpvbmVzLkNsb2Frcm9vbS5Qb3MueikKCVNldEJsaXBTcHJpdGUgKGJsaXAsIDIzNykKCVNldEJsaXBEaXNwbGF5KGJsaXAsIDQpCglTZXRCbGlwU2NhbGUgIChibGlwLCAxLjApCglTZXRCbGlwQ29sb3VyIChibGlwLCA1KQoJU2V0QmxpcEFzU2hvcnRSYW5nZShibGlwLCB0cnVlKQoJQmVnaW5UZXh0Q29tbWFuZFNldEJsaXBOYW1lKCJTVFJJTkciKQoJQWRkVGV4dENvbXBvbmVudFN0cmluZygiRMOpcMO0dCBCdWNoZXJvbiIpCglFbmRUZXh0Q29tbWFuZFNldEJsaXBOYW1lKGJsaXApCmVuZCkKCkNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkJCQoJbG9jYWwgYmxpcCA9IEFkZEJsaXBGb3JDb29yZChDb25maWcuWm9uZXMuV29vZC5Qb3MueCwgQ29uZmlnLlpvbmVzLldvb2QuUG9zLnksIENvbmZpZy5ab25lcy5Xb29kLlBvcy56KQoJU2V0QmxpcFNwcml0ZSAoYmxpcCwgMjM3KQoJU2V0QmxpcERpc3BsYXkoYmxpcCwgNCkKCVNldEJsaXBTY2FsZSAgKGJsaXAsIDEuMCkKCVNldEJsaXBDb2xvdXIgKGJsaXAsIDUpCglTZXRCbGlwQXNTaG9ydFJhbmdlKGJsaXAsIHRydWUpCglCZWdpblRleHRDb21tYW5kU2V0QmxpcE5hbWUoIlNUUklORyIpCglBZGRUZXh0Q29tcG9uZW50U3RyaW5nKCJTY2llcmllIikKCUVuZFRleHRDb21tYW5kU2V0QmxpcE5hbWUoYmxpcCkKZW5kKQoKLS0gRGlzcGxheSBtYXJrZXJzCkNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKCXdoaWxlIHRydWUgZG8JCQoJCVdhaXQoMCkJCQoJCWlmIFBsYXllckRhdGEuam9iIH49IG5pbCBhbmQgUGxheWVyRGF0YS5qb2IubmFtZSA9PSAnbHVtYmVyamFjaycgdGhlbgoKCQkJbG9jYWwgY29vcmRzID0gR2V0RW50aXR5Q29vcmRzKEdldFBsYXllclBlZCgtMSkpCgkJCQoJCQlmb3Igayx2IGluIHBhaXJzKENvbmZpZy5ab25lcykgZG8KCQkJCWlmKHYuVHlwZSB+PSAtMSBhbmQgR2V0RGlzdGFuY2VCZXR3ZWVuQ29vcmRzKGNvb3Jkcywgdi5Qb3MueCwgdi5Qb3MueSwgdi5Qb3MueiwgdHJ1ZSkgPCBDb25maWcuRHJhd0Rpc3RhbmNlKSB0aGVuCgkJCQkJRHJhd01hcmtlcih2LlR5cGUsIHYuUG9zLngsIHYuUG9zLnksIHYuUG9zLnosIDAuMCwgMC4wLCAwLjAsIDAsIDAuMCwgMC4wLCB2LlNpemUueCwgdi5TaXplLnksIHYuU2l6ZS56LCB2LkNvbG9yLnIsIHYuQ29sb3IuZywgdi5Db2xvci5iLCAxMDAsIGZhbHNlLCB0cnVlLCAyLCBmYWxzZSwgZmFsc2UsIGZhbHNlLCBmYWxzZSkKCQkJCWVuZAoJCQllbmQKCQllbmQKCWVuZAplbmQpCgotLSBFbnRlciAvIEV4aXQgbWFya2VyIGV2ZW50cwpDaXRpemVuLkNyZWF0ZVRocmVhZChmdW5jdGlvbigpCgl3aGlsZSB0cnVlIGRvCgkJV2FpdCgwKQoJCWlmIFBsYXllckRhdGEuam9iIH49IG5pbCBhbmQgUGxheWVyRGF0YS5qb2IubmFtZSA9PSAnbHVtYmVyamFjaycgdGhlbgoJCQlsb2NhbCBjb29yZHMgICAgICA9IEdldEVudGl0eUNvb3JkcyhHZXRQbGF5ZXJQZWQoLTEpKQoJCQlsb2NhbCBpc0luTWFya2VyICA9IGZhbHNlCgkJCWxvY2FsIGN1cnJlbnRab25lID0gbmlsCgkJCWZvciBrLHYgaW4gcGFpcnMoQ29uZmlnLlpvbmVzKSBkbwoJCQkJaWYoR2V0RGlzdGFuY2VCZXR3ZWVuQ29vcmRzKGNvb3Jkcywgdi5Qb3MueCwgdi5Qb3MueSwgdi5Qb3MueiwgdHJ1ZSkgPCB2LlNpemUueCkgdGhlbgoJCQkJCWlzSW5NYXJrZXIgID0gdHJ1ZQoJCQkJCWN1cnJlbnRab25lID0gawoJCQkJZW5kCgkJCWVuZAoJCQlpZiAoaXNJbk1hcmtlciBhbmQgbm90IEhhc0FscmVhZHlFbnRlcmVkTWFya2VyKSBvciAoaXNJbk1hcmtlciBhbmQgTGFzdFpvbmUgfj0gY3VycmVudFpvbmUpIHRoZW4KCQkJCUhhc0FscmVhZHlFbnRlcmVkTWFya2VyID0gdHJ1ZQoJCQkJTGFzdFpvbmUgICAgICAgICAgICAgICAgPSBjdXJyZW50Wm9uZQoJCQkJVHJpZ2dlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpoYXNFbnRlcmVkTWFya2VyJywgY3VycmVudFpvbmUpCgkJCWVuZAoJCQlpZiBub3QgaXNJbk1hcmtlciBhbmQgSGFzQWxyZWFkeUVudGVyZWRNYXJrZXIgdGhlbgoJCQkJSGFzQWxyZWFkeUVudGVyZWRNYXJrZXIgPSBmYWxzZQoJCQkJVHJpZ2dlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpoYXNFeGl0ZWRNYXJrZXInLCBMYXN0Wm9uZSkKCQkJZW5kCgkJZW5kCgllbmQKZW5kKQoKLS0gS2V5IENvbnRyb2xzCkNpdGl6ZW4uQ3JlYXRlVGhyZWFkKGZ1bmN0aW9uKCkKICAgIHdoaWxlIHRydWUgZG8KICAgICAgICBDaXRpemVuLldhaXQoMCkKICAgICAgICBpZiBDdXJyZW50QWN0aW9uIH49IG5pbCB0aGVuCiAgICAgICAgICAgIFNldFRleHRDb21wb25lbnRGb3JtYXQoJ1NUUklORycpCiAgICAgICAgICAgIEFkZFRleHRDb21wb25lbnRTdHJpbmcoQ3VycmVudEFjdGlvbk1zZykKICAgICAgICAgICAgRGlzcGxheUhlbHBUZXh0RnJvbVN0cmluZ0xhYmVsKDAsIDAsIDEsIC0xKQogICAgICAgICAgICBpZiBJc0NvbnRyb2xKdXN0UmVsZWFzZWQoMCwgMzgpIGFuZCBQbGF5ZXJEYXRhLmpvYiB+PSBuaWwgYW5kIFBsYXllckRhdGEuam9iLm5hbWUgPT0gJ2x1bWJlcmphY2snIHRoZW4gICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBpZiBDdXJyZW50QWN0aW9uID09ICdsdW1iZXJfYm9zc19tZW51JyB0aGVuCiAgICAgICAgICAgICAgICAgICAgT3Blbkx1bWJlckJvc3NNZW51KCkKICAgICAgICAgICAgICAgIGVuZAogICAgICAgICAgICAgICAgaWYgQ3VycmVudEFjdGlvbiA9PSAnbHVtYmVyX2Nsb2Frcm9vbV9tZW51JyB0aGVuCiAgICAgICAgICAgICAgICAgICAgT3Blbkx1bWJlckNsb2Frcm9vbXRNZW51KCkKICAgICAgICAgICAgICAgIGVuZAogICAgICAgICAgICAgICAgaWYgQ3VycmVudEFjdGlvbiA9PSAnc3Bhd25fdmVoaWNsZV9tZW51JyB0aGVuCiAgICAgICAgICAgICAgICAgICAgT3Blbkx1bWJlclZlaGljbGVNZW51KCkKICAgICAgICAgICAgICAgIGVuZAogICAgICAgICAgICAgICAgaWYgQ3VycmVudEFjdGlvbiA9PSAnaGFydmVzdF93b29kJyB0aGVuCiAgICAgICAgICAgICAgICAgICAgVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpzdGFydEhhcnZlc3RXb29kJykKICAgICAgICAgICAgICAgIGVuZAogICAgICAgICAgICAgICAgaWYgQ3VycmVudEFjdGlvbiA9PSAndHJhbnNmb3JtX2N1dHRlZHdvb2QnIHRoZW4KICAgICAgICAgICAgICAgICAgICBUcmlnZ2VyU2VydmVyRXZlbnQoJ2VzeF9sdW1iZXJqYWNram9iOnN0YXJ0Q3V0aW5nV29vZCcpCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICAgIGlmIEN1cnJlbnRBY3Rpb24gPT0gJ2hhcnZlc3RfcGxhbmsnIHRoZW4KICAgICAgICAgICAgICAgICAgICBUcmlnZ2VyU2VydmVyRXZlbnQoJ2VzeF9sdW1iZXJqYWNram9iOnN0YXJ0UGFja2FnZVBsYW5rJykKICAgICAgICAgICAgICAgIGVuZAogICAgICAgICAgICAgICAgaWYgQ3VycmVudEFjdGlvbiA9PSAncmVzZWxsJyB0aGVuCiAgICAgICAgICAgICAgICAgICAgVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfbHVtYmVyamFja2pvYjpzdGFydFJlc2VsbCcpCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICAgIGlmIEN1cnJlbnRBY3Rpb24gPT0gJ2RlbGV0ZV92ZWhpY2xlJyB0aGVuCiAgICAgICAgICAgICAgICAgICAgbG9jYWwgcGxheWVyUGVkID0gR2V0UGxheWVyUGVkKC0xKQogICAgICAgICAgICAgICAgICAgIGxvY2FsIHZlaGljbGUgICA9IEdldFZlaGljbGVQZWRJc0luKHBsYXllclBlZCwgIGZhbHNlKQogICAgICAgICAgICAgICAgICAgIGxvY2FsIGhhc2ggICAgICA9IEdldEVudGl0eU1vZGVsKHZlaGljbGUpCiAgICAgICAgICAgICAgICAgICAgaWYgaGFzaCA9PSBHZXRIYXNoS2V5KCdwaGFudG9tJykgb3IgaGFzaCA9PSBHZXRIYXNoS2V5KCdwYWNrZXInKSBvciBoYXNoID09IEdldEhhc2hLZXkoJ3BoYW50b20zJykgb3IgaGFzaCA9PSBHZXRIYXNoS2V5KCdiaXNvbjMnKSB0aGVuCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIENvbmZpZy5NYXhJblNlcnZpY2Ugfj0gLTEgdGhlbgogICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJpZ2dlclNlcnZlckV2ZW50KCdlc3hfc2VydmljZTpkaXNhYmxlU2VydmljZScsICdsdW1iZXJqYWNrJykKICAgICAgICAgICAgICAgICAgICAgICAgZW5kICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgIERlbGV0ZVZlaGljbGUodmVoaWNsZSkKICAgICAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICAgICAgICAgIEVTWC5TaG93Tm90aWZpY2F0aW9uKCdWb3VzIG5lIHBvdXZleiByYW5nZXIgcXVlIGRlcyB+Yn52w6loaWN1bGVzIGRlIEJ1Y2hlcm9ufnN+LicpCiAgICAgICAgICAgICAgICAgICAgZW5kCiAgICAgICAgICAgICAgICBlbmQKICAgICAgICAgICAgICAgIEN1cnJlbnRBY3Rpb24gPSBuaWwgICAgICAgICAgICAgICAKICAgICAgICAgICAgZW5kCiAgICAgICAgZW5kCgogICAgICAgIGlmIElzQ29udHJvbEp1c3RSZWxlYXNlZCgwLCAxNjcpIGFuZCBQbGF5ZXJEYXRhLmpvYiB+PSBuaWwgYW5kIFBsYXllckRhdGEuam9iLm5hbWUgPT0gJ2x1bWJlcmphY2snIHRoZW4KICAgICAgICAgICAgT3Blbk1vYmlsZUx1bWJlckFjdGlvbnNNZW51KCkKICAgICAgICBlbmQKICAgIGVuZAplbmQp