/////////////XTREME HACK////////////////
///////////unknowncheats.me/////////////
using Factory = SharpDX.Direct2D1.Factory;
using FontFactory = SharpDX.DirectWrite.Factory;
using SharpDX;
using SharpDX.Windows;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
namespace External_ESP_Base
{
public partial class Overlay : Form
{
// Process
private Thread updateStream
= null, windowStream
= null;
// Game Data
private List<Player> players = null;
private Player localPlayer = null;
private Matrix viewProj, m_ViewMatrixInverse;
private int spectatorCount = 0;
// Keys Control
private KeysManager manager;
// Handle
private IntPtr handle;
// Color
private Color enemyColor
= new Color(255,
0,
0,
200),
enemyColorVisible
= new Color(255,
255,
0,
220),
enemyColorVehicle
= new Color(255,
129,
72,
200),
enemySkeletonColor
= new Color(245,
114,
0,
255),
friendlyColor
= new Color(0,
255,
0,
200),
friendlyColorVehicle
= new Color(64,
154,
200,
255),
friendSkeletonColor
= new Color(46,
228,
213,
255);
// Settings
private bool ESP_Box = true,
ESP_Bone = true,
ESP_Health = false,
ESP_Distance = false,
ESP_Vehicle = true;
// SharpDX
private WindowRenderTarget device;
private HwndRenderTargetProperties renderProperties;
private SolidColorBrush solidColorBrush;
private Factory factory;
private bool IsResize = false;
private bool IsMinimized = false;
// SharpDX Font
private TextFormat font, fontSmall;
private FontFactory fontFactory;
private const string fontFamily = "Calibri";
private const float fontSize = 18.0f;
private const float fontSizeSmall = 14.0f;
// Screen Size
// Init
{
this.process = process;
this.handle = Handle;
int initialStyle = Managed.GetWindowLong(this.Handle, -20);
Managed.SetWindowLong(this.Handle, -20, initialStyle | 0x80000 | 0x20);
IntPtr HWND_TOPMOST = new IntPtr(-1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;
Managed.SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
OnResize(null);
InitializeComponent();
}
// Set window style
protected override void OnResize(EventArgs e)
{
int[] margins = new int[] { 0, 0, rect.Width, rect.Height };
Managed.DwmExtendFrameIntoClientArea(this.Handle, ref margins);
}
// INIT
private void DrawWindow_Load(object sender, EventArgs e)
{
this.TopMost = true;
this.Visible = true;
this.FormBorderStyle = FormBorderStyle.None;
//this.WindowState = FormWindowState.Maximized;
this.Width = rect.Width;
this.Height = rect.Height;
// Window name
this.
Name = Process.
GetCurrentProcess().
ProcessName + "~Overlay"; this.
Text = Process.
GetCurrentProcess().
ProcessName + "~Overlay";
// Init factory
factory = new Factory();
fontFactory = new FontFactory();
// Render settings
renderProperties = new HwndRenderTargetProperties()
{
Hwnd = this.Handle,
PixelSize = new Size2(rect.Width, rect.Height),
PresentOptions = PresentOptions.None
};
// Init device
device
= new WindowRenderTarget
(factory,
new RenderTargetProperties
(new PixelFormat
(Format.
B8G8R8A8_UNorm, AlphaMode.
Premultiplied)), renderProperties
);
// Init brush
solidColorBrush
= new SolidColorBrush
(device,
Color.
White);
// Init font's
font = new TextFormat(fontFactory, fontFamily, fontSize);
fontSmall = new TextFormat(fontFactory, fontFamily, fontSizeSmall);
// Open process
RPM.OpenProcess(process.Id);
// Init player array
players = new List<Player>();
localPlayer = new Player();
// Init update thread
updateStream
= new Thread(new ParameterizedThreadStart
(Update
)); updateStream.Start();
// Init window thread (resize / position)
windowStream
= new Thread(new ParameterizedThreadStart
(SetWindow
)); windowStream.Start();
// Init Key Listener
manager = new KeysManager();
manager.AddKey(Keys.F5);
manager.AddKey(Keys.F6);
manager.AddKey(Keys.F7);
manager.AddKey(Keys.F8);
manager.AddKey(Keys.F9);
//manager.KeyUpEvent += new KeysManager.KeyHandler(KeyUpEvent);
manager.KeyDownEvent += new KeysManager.KeyHandler(KeyDownEvent);
}
// Key Down Event
private void KeyDownEvent(int keyId, string keyName)
{
switch ((Keys)keyId)
{
case Keys.F5:
this.ESP_Box = !this.ESP_Box;
break;
case Keys.F6:
this.ESP_Bone = !this.ESP_Bone;
break;
case Keys.F7:
this.ESP_Health = !this.ESP_Health;
break;
case Keys.F8:
this.ESP_Distance = !this.ESP_Distance;
break;
case Keys.F9:
this.ESP_Vehicle = !this.ESP_Vehicle;
break;
}
}
// FPS Stats
private static int lastTick;
private static int lastFrameRate;
private static int frameRate;
// Check is Game Run
private bool IsGameRun()
{
{
if (p.ProcessName == process.ProcessName)
return true;
}
return false;
}
// Update Thread
private void Update(object sender)
{
while (IsGameRun())
{
// Resize
if (IsResize)
{
device.Resize(new Size2(rect.Width, rect.Height));
//Console.WriteLine("Resize {0}/{1}", rect.Width, rect.Height);
IsResize = false;
}
// Begin Draw
device.BeginDraw();
device.Clear(new Color4(0.0f, 0.0f, 0.0f, 0.0f));
// Check Window State
if (!IsMinimized)
{
// Read & Draw Players
Read();
// Draw Credits
DrawTextCenter
(rect.
Width / 2 - 125,
5,
250,
(int)font.
FontSize,
"EXTERNAL ESP BASE BY XTREME2010",
new Color(255,
214,
0,
255),
true);
// Draw Spectator Count
DrawTextCenter
(rect.
Width / 2 - 100, rect.
Height - (int)font.
FontSize,
200,
(int)font.
FontSize, spectatorCount
+ " SPECTATOR(S) ON A SERVER",
new Color(255,
214,
0,
255),
true);
// Draw Menu
DrawMenu(5, 5);
}
// End Draw
device.EndDraw();
CalculateFrameRate();
//Thread.Sleep(Interval);
}
// Close Process
RPM.CloseProcess();
// Exit
}
// Read Game Memorry
private void Read()
{
// Reset Old Data
players.Clear();
localPlayer = new Player();
// Read Local
#region Get Local Player
Int64 pGContext = RPM.Read<Int64>(Offsets.ClientGameContext.GetInstance());
if (!RPM.IsValid(pGContext))
return;
Int64 pPlayerManager = RPM.Read<Int64>(pGContext + Offsets.ClientGameContext.m_pPlayerManager);
if (!RPM.IsValid(pPlayerManager))
return;
Int64 pLocalPlayer = RPM.Read<Int64>(pPlayerManager + Offsets.ClientPlayerManager.m_pLocalPlayer);
if (!RPM.IsValid(pLocalPlayer))
return;
//RPM.Read<Int64>(pLocalPlayer + Offsets.ClientPlayer.m_pControlledControllable);
Int64 pLocalSoldier = GetClientSoldierEntity(pLocalPlayer, localPlayer);
if (!RPM.IsValid(pLocalSoldier))
return;
Int64 pHealthComponent = RPM.Read<Int64>(pLocalSoldier + Offsets.ClientSoldierEntity.m_pHealthComponent);
if (!RPM.IsValid(pHealthComponent))
return;
Int64 m_pPredictedController = RPM.Read<Int64>(pLocalSoldier + Offsets.ClientSoldierEntity.m_pPredictedController);
if (!RPM.IsValid(m_pPredictedController))
return;
// Health
localPlayer.Health = RPM.Read<float>(pHealthComponent + Offsets.HealthComponent.m_Health);
localPlayer.MaxHealth = RPM.Read<float>(pHealthComponent + Offsets.HealthComponent.m_MaxHealth);
if (localPlayer.Health <= 0.1f) // YOU DEAD :D
return;
// Origin
localPlayer.Origin = RPM.Read<Vector3>(m_pPredictedController + Offsets.ClientSoldierPrediction.m_Position);
// Other
localPlayer.Team = RPM.Read<Int32>(pLocalPlayer + Offsets.ClientPlayer.m_teamId);
//localPlayer.Name = RPM.ReadString(pLocalPlayer + Offsets.ClientPlayer.szName, 10);
localPlayer.Pose = RPM.Read<Int32>(pLocalSoldier + Offsets.ClientSoldierEntity.m_poseType);
localPlayer.Yaw = RPM.Read<float>(pLocalSoldier + Offsets.ClientSoldierEntity.m_authorativeYaw);
localPlayer.IsOccluded = RPM.Read<Byte>(pLocalSoldier + Offsets.ClientSoldierEntity.m_occluded);
// Weapon Ammo
if (localPlayer.InVehicle)
{
Int64 pCurrentWeaponFiring = RPM.Read<Int64>(Offsets.OFFSET_CURRENT_WEAPONFIRING);
if (RPM.IsValid(pCurrentWeaponFiring))
{
// Ammo
localPlayer.Ammo = RPM.Read<Int32>(pCurrentWeaponFiring + Offsets.WeaponFiring.m_projectilesLoaded);
localPlayer.AmmoClip = RPM.Read<Int32>(pCurrentWeaponFiring + Offsets.WeaponFiring.m_projectilesInMagazines);
}
}
else
{
Int64 pClientWeaponComponent = RPM.Read<Int64>(pLocalSoldier + Offsets.ClientSoldierEntity.m_soldierWeaponsComponent);
if (RPM.IsValid(pClientWeaponComponent))
{
Int64 pWeaponHandle = RPM.Read<Int64>(pClientWeaponComponent + Offsets.ClientSoldierWeaponsComponent.m_handler);
Int32 ActiveSlot = RPM.Read<Int32>(pClientWeaponComponent + Offsets.ClientSoldierWeaponsComponent.m_activeSlot);
if (RPM.IsValid(pWeaponHandle))
{
Int64 pSoldierWeapon = RPM.Read<Int64>(pWeaponHandle + ActiveSlot * 0x8);
if (RPM.IsValid(pSoldierWeapon))
{
Int64 pCorrectedFiring = RPM.Read<Int64>(pSoldierWeapon + Offsets.ClientSoldierWeapon.m_pPrimary);
if (RPM.IsValid(pCorrectedFiring))
{
// Ammo
localPlayer.Ammo = RPM.Read<Int32>(pCorrectedFiring + Offsets.WeaponFiring.m_projectilesLoaded);
localPlayer.AmmoClip = RPM.Read<Int32>(pCorrectedFiring + Offsets.WeaponFiring.m_projectilesInMagazines);
}
}
}
}
}
#endregion
// Render View
Int64 pGameRenderer = RPM.Read<Int64>(Offsets.GameRenderer.GetInstance());
Int64 pRenderView = RPM.Read<Int64>(pGameRenderer + Offsets.GameRenderer.m_pRenderView);
// Read Screen Matrix
viewProj = RPM.Read<Matrix>(pRenderView + Offsets.RenderView.m_ViewProj);
m_ViewMatrixInverse = RPM.Read<Matrix>(pRenderView + Offsets.RenderView.m_ViewMatrixInverse);
// Pointer to Players Array
Int64 m_ppPlayer = RPM.Read<Int64>(pPlayerManager + Offsets.ClientPlayerManager.m_ppPlayer);
if (!RPM.IsValid(m_ppPlayer))
return;
// Reset
spectatorCount = 0;
// Get Player by Id
#region Get Player by Id
for (uint i = 0; i < 70; i++)
{
// Create new Player
Player player = new Player();
// Pointer to ClientPlayer class (Player Array + (Id * Size of Pointer))
Int64 pEnemyPlayer = RPM.Read<Int64>(m_ppPlayer + (i * sizeof(Int64)));
if (!RPM.IsValid(pEnemyPlayer))
continue;
//if (pEnemyPlayer == pLocalPlayer)
// continue;
player.IsSpectator = Convert.ToBoolean(RPM.Read<Byte>(pEnemyPlayer + Offsets.ClientPlayer.m_isSpectator));
if (player.IsSpectator)
spectatorCount++;
// Name
player.
Name = RPM.
ReadString(pEnemyPlayer
+ Offsets.
ClientPlayer.
szName,
10);
// RPM.Read<Int64>(pEnemyPlayer + Offsets.ClientPlayer.m_pControlledControllable);
Int64 pEnemySoldier = GetClientSoldierEntity(pEnemyPlayer, player);
if (!RPM.IsValid(pEnemySoldier))
continue;
Int64 pEnemyHealthComponent = RPM.Read<Int64>(pEnemySoldier + Offsets.ClientSoldierEntity.m_pHealthComponent);
if (!RPM.IsValid(pEnemyHealthComponent))
continue;
Int64 pEnemyPredictedController = RPM.Read<Int64>(pEnemySoldier + Offsets.ClientSoldierEntity.m_pPredictedController);
if (!RPM.IsValid(pEnemyPredictedController))
continue;
// Health
player.Health = RPM.Read<float>(pEnemyHealthComponent + Offsets.HealthComponent.m_Health);
player.MaxHealth = RPM.Read<float>(pEnemyHealthComponent + Offsets.HealthComponent.m_MaxHealth);
if (player.Health <= 0.1f) // DEAD
continue;
// Origin (Position in Game X, Y, Z)
player.Origin = RPM.Read<Vector3>(pEnemyPredictedController + Offsets.ClientSoldierPrediction.m_Position);
// Other
player.Team = RPM.Read<Int32>(pEnemyPlayer + Offsets.ClientPlayer.m_teamId);
player.Pose = RPM.Read<Int32>(pEnemySoldier + Offsets.ClientSoldierEntity.m_poseType);
player.Yaw = RPM.Read<float>(pEnemySoldier + Offsets.ClientSoldierEntity.m_authorativeYaw);
player.IsOccluded = RPM.Read<Byte>(pEnemySoldier + Offsets.ClientSoldierEntity.m_occluded);
// Distance to You
player.Distance = Vector3.Distance(localPlayer.Origin, player.Origin);
if (player.IsValid())
{
#region Bone ESP
if (ESP_Bone)
{
// Player Bone
if (GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_HEAD, out player.Bone.BONE_HEAD)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_LEFTELBOWROLL, out player.Bone.BONE_LEFTELBOWROLL)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_LEFTFOOT, out player.Bone.BONE_LEFTFOOT)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_LEFTHAND, out player.Bone.BONE_LEFTHAND)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_LEFTKNEEROLL, out player.Bone.BONE_LEFTKNEEROLL)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_LEFTSHOULDER, out player.Bone.BONE_LEFTSHOULDER)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_NECK, out player.Bone.BONE_NECK)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_RIGHTELBOWROLL, out player.Bone.BONE_RIGHTELBOWROLL)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_RIGHTFOOT, out player.Bone.BONE_RIGHTFOOT)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_RIGHTHAND, out player.Bone.BONE_RIGHTHAND)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_RIGHTKNEEROLL, out player.Bone.BONE_RIGHTKNEEROLL)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_RIGHTSHOULDER, out player.Bone.BONE_RIGHTSHOULDER)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_SPINE, out player.Bone.BONE_SPINE)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_SPINE1, out player.Bone.BONE_SPINE1)
&& GetBonyById(pEnemySoldier, (int)Offsets.UpdatePoseResultData.BONES.BONE_SPINE2, out player.Bone.BONE_SPINE2))
{
DrawBone(player);
}
}
#endregion
Vector3 w2sFoot, w2sHead;
if (WorldToScreen(player.Origin, out w2sFoot) &&
WorldToScreen(player.Origin, player.Pose, out w2sHead))
{
float H = w2sFoot.Y - w2sHead.Y;
float W = H / 2;
float X = w2sHead.X - W / 2;
if (player.Team == localPlayer.Team) {
color = friendlyColor;
}
else {
color = player.IsVisible() ? enemyColorVisible : enemyColor;
}
#endregion
#region Draw ESP
// ESP Box
if (ESP_Box)
{
DrawAABB(player.GetAABB(), player.Origin, player.Yaw, color);
//DrawRect((int)X, (int)Head.Y, (int)BoxWidth, (int)HeadToFoot, color);
}
// ESP Vehicle
if (ESP_Vehicle)
{
DrawAABB(player.VehicleAABB, player.VehicleTranfsorm, player.Team == localPlayer.Team ? friendlyColorVehicle : enemyColorVehicle);
}
// ESP Distance
if (ESP_Distance)
{
DrawText
((int)X,
(int)w2sFoot.
Y,
(int)player.
Distance + "m",
Color.
White,
true); }
// ESP Health
if (ESP_Health)
{
DrawHealth((int)X, (int)w2sHead.Y - 6, (int)W, 3, (int)player.Health, (int)player.MaxHealth);
// Vehicle Health
if (player.InVehicle && player.IsDriver)
{
DrawHealth((int)X, (int)w2sHead.Y - 10, (int)W, 3, (int)player.VehicleHealth, (int)player.VehicleMaxHealth);
}
}
#endregion
}
}
// ADD IN ARRAY
players.Add(player);
}
#endregion
// Check Spectator Count
if (spectatorCount > 0)
{
DrawWarn(rect.Center.X - 125, 25, 250, 55);
}
}
// Get SoldierEntity
private Int64 GetClientSoldierEntity(Int64 pClientPlayer, Player player)
{
Int64 pAttached = RPM.Read<Int64>(pClientPlayer + Offsets.ClientPlayer.m_pAttachedControllable);
if (RPM.IsValid(pAttached))
{
Int64 m_ClientSoldier = RPM.Read<Int64>(RPM.Read<Int64>(pClientPlayer + Offsets.ClientPlayer.m_character)) - sizeof(Int64);
if (RPM.IsValid(m_ClientSoldier))
{
player.InVehicle = true;
Int64 pVehicleEntity = RPM.Read<Int64>(pClientPlayer + Offsets.ClientPlayer.m_pAttachedControllable);
if (RPM.IsValid(pVehicleEntity))
{
// Driver
if (RPM.Read<Int32>(pClientPlayer + Offsets.ClientPlayer.m_attachedEntryId) == 0)
{
// Vehicle AABB
if (ESP_Vehicle)
{
Int64 pDynamicPhysicsEntity = RPM.Read<Int64>(pVehicleEntity + Offsets.ClientVehicleEntity.m_pPhysicsEntity);
if (RPM.IsValid(pDynamicPhysicsEntity))
{
Int64 pPhysicsEntity = RPM.Read<Int64>(pDynamicPhysicsEntity + Offsets.DynamicPhysicsEntity.m_EntityTransform);
player.VehicleTranfsorm = RPM.Read<Matrix>(pPhysicsEntity + Offsets.PhysicsEntityTransform.m_Transform);
player.VehicleAABB = RPM.Read<AxisAlignedBox>(pVehicleEntity + Offsets.ClientVehicleEntity.m_childrenAABB);
}
}
Int64 _EntityData = RPM.Read<Int64>(pVehicleEntity + Offsets.ClientSoldierEntity.m_data);
if (RPM.IsValid(_EntityData))
{
Int64 _NameSid = RPM.Read<Int64>(_EntityData + Offsets.VehicleEntityData.m_NameSid);
string strName = RPM.ReadName(_NameSid, 20);
if (strName.Length > 11)
{
Int64 pAttachedClient = RPM.Read<Int64>(m_ClientSoldier + Offsets.ClientSoldierEntity.m_pPlayer);
// AttachedControllable Max Health
Int64 p = RPM.Read<Int64>(pAttachedClient + Offsets.ClientPlayer.m_pAttachedControllable);
Int64 p2 = RPM.Read<Int64>(p + Offsets.ClientSoldierEntity.m_pHealthComponent);
player.VehicleHealth = RPM.Read<float>(p2 + Offsets.HealthComponent.m_vehicleHealth);
// AttachedControllable Health
player.VehicleMaxHealth = RPM.Read<float>(_EntityData + Offsets.VehicleEntityData.m_FrontMaxHealth);
// AttachedControllable Name
player.VehicleName = strName.Remove(0, 11);
player.IsDriver = true;
}
}
}
}
}
return m_ClientSoldier;
}
return RPM.Read<Int64>(pClientPlayer + Offsets.ClientPlayer.m_pControlledControllable);
}
// Get Window Rect
private void SetWindow(object sender)
{
while (true)
{
IntPtr targetWnd = IntPtr.Zero;
targetWnd = Managed.FindWindow(null, "Battlefield 4");
if (targetWnd != IntPtr.Zero)
{
RECT targetSize = new RECT();
Managed.GetWindowRect(targetWnd, out targetSize);
// Game is Minimized
if (targetSize.Left < 0 && targetSize.Top < 0 && targetSize.Right < 0 && targetSize.Bottom < 0)
{
IsMinimized = true;
continue;
}
// Reset
IsMinimized = false;
RECT borderSize = new RECT();
Managed.GetClientRect(targetWnd, out borderSize);
int dwStyle = Managed.GetWindowLong(targetWnd, Managed.GWL_STYLE);
int windowheight;
int windowwidth;
int borderheight;
int borderwidth;
if (rect.Width != (targetSize.Bottom - targetSize.Top)
&& rect.Width != (borderSize.Right - borderSize.Left))
IsResize = true;
rect.Width = targetSize.Right - targetSize.Left;
rect.Height = targetSize.Bottom - targetSize.Top;
if ((dwStyle & Managed.WS_BORDER) != 0)
{
windowheight = targetSize.Bottom - targetSize.Top;
windowwidth = targetSize.Right - targetSize.Left;
rect.Height = borderSize.Bottom - borderSize.Top;
rect.Width = borderSize.Right - borderSize.Left;
borderheight = (windowheight - borderSize.Bottom);
borderwidth = (windowwidth - borderSize.Right) / 2; //only want one side
borderheight -= borderwidth; //remove bottom
targetSize.Left += borderwidth;
targetSize.Top += borderheight;
rect.Left = targetSize.Left;
rect.Top = targetSize.Top;
}
Managed.MoveWindow(handle, targetSize.Left, targetSize.Top, rect.Width, rect.Height, true);
}
}
}
// 3D In 2D
private bool WorldToScreen(Vector3 _Enemy, int _Pose, out Vector3 _Screen)
{
_Screen = new Vector3(0, 0, 0);
float HeadHeight = _Enemy.Y;
#region HeadHeight
if (_Pose == 0)
{
HeadHeight += 1.7f;
}
if (_Pose == 1)
{
HeadHeight += 1.15f;
}
if (_Pose == 2)
{
HeadHeight += 0.4f;
}
#endregion
float ScreenW = (viewProj.M14 * _Enemy.X) + (viewProj.M24 * HeadHeight) + (viewProj.M34 * _Enemy.Z + viewProj.M44);
if (ScreenW < 0.0001f)
return false;
float ScreenX = (viewProj.M11 * _Enemy.X) + (viewProj.M21 * HeadHeight) + (viewProj.M31 * _Enemy.Z + viewProj.M41);
float ScreenY = (viewProj.M12 * _Enemy.X) + (viewProj.M22 * HeadHeight) + (viewProj.M32 * _Enemy.Z + viewProj.M42);
_Screen.X = (rect.Width / 2) + (rect.Width / 2) * ScreenX / ScreenW;
_Screen.Y = (rect.Height / 2) - (rect.Height / 2) * ScreenY / ScreenW;
_Screen.Z = ScreenW;
return true;
}
// 3D In 2D
private bool WorldToScreen(Vector3 _Enemy, out Vector3 _Screen)
{
_Screen = new Vector3(0, 0, 0);
float ScreenW = (viewProj.M14 * _Enemy.X) + (viewProj.M24 * _Enemy.Y) + (viewProj.M34 * _Enemy.Z + viewProj.M44);
if (ScreenW < 0.0001f)
return false;
float ScreenX = (viewProj.M11 * _Enemy.X) + (viewProj.M21 * _Enemy.Y) + (viewProj.M31 * _Enemy.Z + viewProj.M41);
float ScreenY = (viewProj.M12 * _Enemy.X) + (viewProj.M22 * _Enemy.Y) + (viewProj.M32 * _Enemy.Z + viewProj.M42);
_Screen.X = (rect.Width / 2) + (rect.Width / 2) * ScreenX / ScreenW;
_Screen.Y = (rect.Height / 2) - (rect.Height / 2) * ScreenY / ScreenW;
_Screen.Z = ScreenW;
return true;
}
// Get Roll
private bool GetBonyById(Int64 pEnemySoldier, int Id, out Vector3 _World)
{
_World = new Vector3();
Int64 pRagdollComp = RPM.Read<Int64>(pEnemySoldier + Offsets.ClientSoldierEntity.m_ragdollComponent);
if (!RPM.IsValid(pRagdollComp))
return false;
byte m_ValidTransforms = RPM.Read<Byte>(pRagdollComp + (Offsets.ClientRagDollComponent.m_ragdollTransforms + Offsets.UpdatePoseResultData.m_ValidTransforms));
if (m_ValidTransforms != 1)
return false;
Int64 pQuatTransform = RPM.Read<Int64>(pRagdollComp + (Offsets.ClientRagDollComponent.m_ragdollTransforms + Offsets.UpdatePoseResultData.m_ActiveWorldTransforms));
if (!RPM.IsValid(pQuatTransform))
return false;
_World = RPM.Read<Vector3>(pQuatTransform + Id * 0x20);
return true;
}
// Get FPS
public int CalculateFrameRate()
{
if (tickCount - lastTick >= 1000)
{
lastFrameRate = frameRate;
frameRate = 0;
lastTick = tickCount;
}
frameRate++;
return lastFrameRate;
}
// Close window event
private void DrawWindow_FormClosing(object sender, FormClosingEventArgs e)
{
updateStream.Abort();
windowStream.Abort();
RPM.CloseProcess();
// Close main process
}
// Multiply Vector's
public Vector3 Multiply(Vector3 vector, Matrix mat)
{
return new Vector3(mat.M11 * vector.X + mat.M21 * vector.Y + mat.M31 * vector.Z,
mat.M12 * vector.X + mat.M22 * vector.Y + mat.M32 * vector.Z,
mat.M13 * vector.X + mat.M23 * vector.Y + mat.M33 * vector.Z);
}
// Draw Functions
#region Draw Functions
private void DrawRect
(int X,
int Y,
int W,
int H,
Color color
) {
solidColorBrush.
Color = color
; device.
DrawRectangle(new Rectangle(X, Y, W, H
), solidColorBrush
); }
private void DrawRect
(int X,
int Y,
int W,
int H,
Color color,
float stroke
) {
solidColorBrush.
Color = color
; device.
DrawRectangle(new Rectangle(X, Y, W, H
), solidColorBrush, stroke
); }
private void DrawFillRect
(int X,
int Y,
int W,
int H,
Color color
) {
solidColorBrush.
Color = color
; device.FillRectangle(new RectangleF(X, Y, W, H), solidColorBrush);
}
private void DrawText
(int X,
int Y, string text,
Color color
) {
solidColorBrush.
Color = color
; device.DrawText(text, font, new RectangleF(X, Y, font.FontSize * text.Length, font.FontSize), solidColorBrush);
}
private void DrawText
(int X,
int Y, string text,
Color color, bool outline
) {
if (outline)
{
device.DrawText(text, font, new RectangleF(X + 1, Y + 1, font.FontSize * text.Length, font.FontSize), solidColorBrush);
}
solidColorBrush.
Color = color
; device.DrawText(text, font, new RectangleF(X, Y, font.FontSize * text.Length, font.FontSize), solidColorBrush);
}
private void DrawText
(int X,
int Y, string text,
Color color, bool outline, TextFormat format
) {
if (outline)
{
device.DrawText(text, format, new RectangleF(X + 1, Y + 1, format.FontSize * text.Length, format.FontSize), solidColorBrush);
}
solidColorBrush.
Color = color
; device.DrawText(text, format, new RectangleF(X, Y, format.FontSize * text.Length, format.FontSize), solidColorBrush);
}
private void DrawTextCenter
(int X,
int Y,
int W,
int H, string text,
Color color
) {
solidColorBrush.
Color = color
; layout.TextAlignment = TextAlignment.Center;
device.DrawTextLayout(new Vector2(X, Y), layout, solidColorBrush);
layout.Dispose();
}
private void DrawTextCenter
(int X,
int Y,
int W,
int H, string text,
Color color, bool outline
) {
layout.TextAlignment = TextAlignment.Center;
if (outline)
{
device.DrawTextLayout(new Vector2(X + 1, Y + 1), layout, solidColorBrush);
}
solidColorBrush.
Color = color
; device.DrawTextLayout(new Vector2(X, Y), layout, solidColorBrush);
layout.Dispose();
}
private void DrawLine
(int X,
int Y,
int XX,
int YY,
Color color
) {
solidColorBrush.
Color = color
; device.DrawLine(new Vector2(X, Y), new Vector2(XX, YY), solidColorBrush);
}
private void DrawLine
(Vector3 w2s, Vector3 _w2s,
Color color
) {
solidColorBrush.
Color = color
; device.DrawLine(new Vector2(w2s.X, w2s.Y), new Vector2(_w2s.X, _w2s.Y), solidColorBrush);
}
private void DrawCircle
(int X,
int Y,
int W,
Color color
) {
solidColorBrush.
Color = color
; device.DrawEllipse(new Ellipse(new Vector2(X, Y), W, W), solidColorBrush);
}
private void DrawFillCircle
(int X,
int Y,
int W,
Color color
) {
solidColorBrush.
Color = color
; device.FillEllipse(new Ellipse(new Vector2(X, Y), W, W), solidColorBrush);
}
private void DrawImage(int X, int Y, int W, int H, Bitmap bitmap)
{
device.DrawBitmap(bitmap, new RectangleF(X, Y, W, H), 1.0f, BitmapInterpolationMode.Linear);
}
private void DrawImage(int X, int Y, int W, int H, Bitmap bitmap, float angle)
{
device.Transform = Matrix3x2.Rotation(angle, new Vector2(X + (H / 2), Y + (H / 2)));
device.DrawBitmap(bitmap, new RectangleF(X, Y, W, H), 1.0f, BitmapInterpolationMode.Linear);
device.Transform = Matrix3x2.Rotation(0);
}
private void DrawSprite(RectangleF destinationRectangle, Bitmap bitmap, RectangleF sourceRectangle)
{
device.DrawBitmap(bitmap, destinationRectangle, 1.0f, BitmapInterpolationMode.Linear, sourceRectangle);
}
private void DrawSprite(RectangleF destinationRectangle, Bitmap bitmap, RectangleF sourceRectangle, float angle)
{
Vector2 center = new Vector2();
center.X = destinationRectangle.X + destinationRectangle.Width / 2;
center.Y = destinationRectangle.Y + destinationRectangle.Height / 2;
device.Transform = Matrix3x2.Rotation(angle, center);
device.DrawBitmap(bitmap, destinationRectangle, 1.0f, BitmapInterpolationMode.Linear, sourceRectangle);
device.Transform = Matrix3x2.Rotation(0);
}
private void DrawBone(Player player)
{
Vector3 BONE_HEAD,
BONE_NECK,
BONE_SPINE2,
BONE_SPINE1,
BONE_SPINE,
BONE_LEFTSHOULDER,
BONE_RIGHTSHOULDER,
BONE_LEFTELBOWROLL,
BONE_RIGHTELBOWROLL,
BONE_LEFTHAND,
BONE_RIGHTHAND,
BONE_LEFTKNEEROLL,
BONE_RIGHTKNEEROLL,
BONE_LEFTFOOT,
BONE_RIGHTFOOT;
if(WorldToScreen(player.Bone.BONE_HEAD, out BONE_HEAD) &&
WorldToScreen(player.Bone.BONE_NECK, out BONE_NECK) &&
WorldToScreen(player.Bone.BONE_SPINE2, out BONE_SPINE2) &&
WorldToScreen(player.Bone.BONE_SPINE1, out BONE_SPINE1) &&
WorldToScreen(player.Bone.BONE_SPINE, out BONE_SPINE) &&
WorldToScreen(player.Bone.BONE_LEFTSHOULDER, out BONE_LEFTSHOULDER) &&
WorldToScreen(player.Bone.BONE_RIGHTSHOULDER, out BONE_RIGHTSHOULDER) &&
WorldToScreen(player.Bone.BONE_LEFTELBOWROLL, out BONE_LEFTELBOWROLL) &&
WorldToScreen(player.Bone.BONE_RIGHTELBOWROLL, out BONE_RIGHTELBOWROLL) &&
WorldToScreen(player.Bone.BONE_LEFTHAND, out BONE_LEFTHAND) &&
WorldToScreen(player.Bone.BONE_RIGHTHAND, out BONE_RIGHTHAND) &&
WorldToScreen(player.Bone.BONE_LEFTKNEEROLL, out BONE_LEFTKNEEROLL) &&
WorldToScreen(player.Bone.BONE_RIGHTKNEEROLL, out BONE_RIGHTKNEEROLL) &&
WorldToScreen(player.Bone.BONE_LEFTFOOT, out BONE_LEFTFOOT) &&
WorldToScreen(player.Bone.BONE_RIGHTFOOT, out BONE_RIGHTFOOT))
{
int stroke = 3;
int strokeW = stroke % 2 == 0 ? stroke / 2 : (stroke - 1) / 2;
// Color
Color skeletonColor
= player.
Team == localPlayer.
Team ? friendSkeletonColor
: enemySkeletonColor
;
// RECT's
DrawFillRect((int)BONE_HEAD.X - strokeW, (int)BONE_HEAD.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_NECK.X - strokeW, (int)BONE_NECK.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_LEFTSHOULDER.X - strokeW, (int)BONE_LEFTSHOULDER.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_LEFTELBOWROLL.X - strokeW, (int)BONE_LEFTELBOWROLL.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_LEFTHAND.X - strokeW, (int)BONE_LEFTHAND.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_RIGHTSHOULDER.X - strokeW, (int)BONE_RIGHTSHOULDER.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_RIGHTELBOWROLL.X - strokeW, (int)BONE_RIGHTELBOWROLL.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_RIGHTHAND.X - strokeW, (int)BONE_RIGHTHAND.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_SPINE2.X - strokeW, (int)BONE_SPINE2.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_SPINE1.X - strokeW, (int)BONE_SPINE1.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_SPINE.X - strokeW, (int)BONE_SPINE.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_LEFTKNEEROLL.X - strokeW, (int)BONE_LEFTKNEEROLL.Y - strokeW, stroke, stroke, skeletonColor);
DrawFillRect((int)BONE_RIGHTKNEEROLL.X - strokeW, (int)BONE_RIGHTKNEEROLL.Y - strokeW, 2, 2, skeletonColor);
DrawFillRect((int)BONE_LEFTFOOT.X - strokeW, (int)BONE_LEFTFOOT.Y - strokeW, 2, 2, skeletonColor);
DrawFillRect((int)BONE_RIGHTFOOT.X - strokeW, (int)BONE_RIGHTFOOT.Y - strokeW, 2, 2, skeletonColor);
// Head -> Neck
DrawLine((int)BONE_HEAD.X, (int)BONE_HEAD.Y, (int)BONE_NECK.X, (int)BONE_NECK.Y, skeletonColor);
// Neck -> Left
DrawLine((int)BONE_NECK.X, (int)BONE_NECK.Y, (int)BONE_LEFTSHOULDER.X, (int)BONE_LEFTSHOULDER.Y, skeletonColor);
DrawLine((int)BONE_LEFTSHOULDER.X, (int)BONE_LEFTSHOULDER.Y,(int) BONE_LEFTELBOWROLL.X, (int)BONE_LEFTELBOWROLL.Y, skeletonColor);
DrawLine((int)BONE_LEFTELBOWROLL.X, (int)BONE_LEFTELBOWROLL.Y, (int)BONE_LEFTHAND.X, (int)BONE_LEFTHAND.Y, skeletonColor);
// Neck -> Right
DrawLine((int)BONE_NECK.X, (int)BONE_NECK.Y, (int)BONE_RIGHTSHOULDER.X, (int)BONE_RIGHTSHOULDER.Y, skeletonColor);
DrawLine((int)BONE_RIGHTSHOULDER.X, (int)BONE_RIGHTSHOULDER.Y, (int)BONE_RIGHTELBOWROLL.X, (int)BONE_RIGHTELBOWROLL.Y, skeletonColor);
DrawLine((int)BONE_RIGHTELBOWROLL.X, (int)BONE_RIGHTELBOWROLL.Y, (int)BONE_RIGHTHAND.X, (int)BONE_RIGHTHAND.Y, skeletonColor);
// Neck -> Center
DrawLine((int)BONE_NECK.X, (int)BONE_NECK.Y, (int)BONE_SPINE2.X, (int)BONE_SPINE2.Y, skeletonColor);
DrawLine((int)BONE_SPINE2.X, (int)BONE_SPINE2.Y, (int)BONE_SPINE1.X, (int)BONE_SPINE1.Y, skeletonColor);
DrawLine((int)BONE_SPINE1.X, (int)BONE_SPINE1.Y, (int)BONE_SPINE.X, (int)BONE_SPINE.Y, skeletonColor);
// Spine -> Left
DrawLine((int)BONE_SPINE.X, (int)BONE_SPINE.Y, (int)BONE_LEFTKNEEROLL.X, (int)BONE_LEFTKNEEROLL.Y, skeletonColor);
DrawLine((int)BONE_LEFTKNEEROLL.X, (int)BONE_LEFTKNEEROLL.Y, (int)BONE_LEFTFOOT.X, (int)BONE_LEFTFOOT.Y, skeletonColor);
// Spine -> Right
DrawLine((int)BONE_SPINE.X, (int)BONE_SPINE.Y, (int)BONE_RIGHTKNEEROLL.X, (int)BONE_RIGHTKNEEROLL.Y, skeletonColor);
DrawLine((int)BONE_RIGHTKNEEROLL.X, (int)BONE_RIGHTKNEEROLL.Y, (int)BONE_RIGHTFOOT.X, (int)BONE_RIGHTFOOT.Y, skeletonColor);
}
}
private void DrawHealth(int X, int Y, int W, int H, int Health, int MaxHealth)
{
if (Health <= 0)
Health = 1;
if (MaxHealth < Health)
MaxHealth = 100;
int progress = (int)((float)Health / ((float)MaxHealth / 100));
int w = (int)((float)W / 100 * progress);
if (w <= 2)
w = 3;
if (progress
>= 20) color
= new Color(255,
165,
0,
255); if (progress
>= 40) color
= new Color(255,
255,
0,
255); if (progress
>= 60) color
= new Color(173,
255,
47,
255); if (progress
>= 80) color
= new Color(0,
255,
0,
255);
DrawFillRect
(X, Y
- 1, W
+ 1, H
+ 2,
Color.
Black); DrawFillRect(X + 1, Y, w - 1, H, color);
}
private void DrawProgress(int X, int Y, int W, int H, int Value, int MaxValue)
{
int progress = (int)((float)Value / ((float)MaxValue / 100));
int w = (int)((float)W / 100 * progress);
if (progress
>= 20) color
= new Color(173,
255,
47,
255); if (progress
>= 40) color
= new Color(255,
255,
0,
255); if (progress
>= 60) color
= new Color(255,
165,
0,
255); if (progress
>= 80) color
= new Color(255,
0,
0,
255);
DrawFillRect
(X, Y
- 1, W
+ 1, H
+ 2,
Color.
Black); if (w >= 2)
{
DrawFillRect(X + 1, Y, w - 1, H, color);
}
}
private void DrawAABB
(AxisAlignedBox aabb, Matrix tranform,
Color color
) {
Vector3 m_Position = new Vector3(tranform.M41, tranform.M42, tranform.M43);
Vector3 fld = Multiply(new Vector3(aabb.Min.X, aabb.Min.Y, aabb.Min.Z), tranform) + m_Position;
Vector3 brt = Multiply(new Vector3(aabb.Max.X, aabb.Max.Y, aabb.Max.Z), tranform) + m_Position;
Vector3 bld = Multiply(new Vector3(aabb.Min.X, aabb.Min.Y, aabb.Max.Z), tranform) + m_Position;
Vector3 frt = Multiply(new Vector3(aabb.Max.X, aabb.Max.Y, aabb.Min.Z), tranform) + m_Position;
Vector3 frd = Multiply(new Vector3(aabb.Max.X, aabb.Min.Y, aabb.Min.Z), tranform) + m_Position;
Vector3 brb = Multiply(new Vector3(aabb.Max.X, aabb.Min.Y, aabb.Max.Z), tranform) + m_Position;
Vector3 blt = Multiply(new Vector3(aabb.Min.X, aabb.Max.Y, aabb.Max.Z), tranform) + m_Position;
Vector3 flt = Multiply(new Vector3(aabb.Min.X, aabb.Max.Y, aabb.Min.Z), tranform) + m_Position;
#region WorldToScreen
if (!WorldToScreen(fld, out fld) || !WorldToScreen(brt, out brt)
|| !WorldToScreen(bld, out bld) || !WorldToScreen(frt, out frt)
|| !WorldToScreen(frd, out frd) || !WorldToScreen(brb, out brb)
|| !WorldToScreen(blt, out blt) || !WorldToScreen(flt, out flt))
return;
#endregion
#region DrawLines
DrawLine(fld, flt, color);
DrawLine(flt, frt, color);
DrawLine(frt, frd, color);
DrawLine(frd, fld, color);
DrawLine(bld, blt, color);
DrawLine(blt, brt, color);
DrawLine(brt, brb, color);
DrawLine(brb, bld, color);
DrawLine(fld, bld, color);
DrawLine(frd, brb, color);
DrawLine(flt, blt, color);
DrawLine(frt, brt, color);
#endregion
}
private void DrawAABB
(AxisAlignedBox aabb, Vector3 m_Position,
float Yaw,
Color color
) {
float cosY
= (float)Math.
Cos(Yaw
); float sinY
= (float)Math.
Sin(Yaw
);
Vector3 fld = new Vector3(aabb.Min.Z * cosY - aabb.Min.X * sinY, aabb.Min.Y, aabb.Min.X * cosY + aabb.Min.Z * sinY) + m_Position; // 0
Vector3 brt = new Vector3(aabb.Min.Z * cosY - aabb.Max.X * sinY, aabb.Min.Y, aabb.Max.X * cosY + aabb.Min.Z * sinY) + m_Position; // 1
Vector3 bld = new Vector3(aabb.Max.Z * cosY - aabb.Max.X * sinY, aabb.Min.Y, aabb.Max.X * cosY + aabb.Max.Z * sinY) + m_Position; // 2
Vector3 frt = new Vector3(aabb.Max.Z * cosY - aabb.Min.X * sinY, aabb.Min.Y, aabb.Min.X * cosY + aabb.Max.Z * sinY) + m_Position; // 3
Vector3 frd = new Vector3(aabb.Max.Z * cosY - aabb.Min.X * sinY, aabb.Max.Y, aabb.Min.X * cosY + aabb.Max.Z * sinY) + m_Position; // 4
Vector3 brb = new Vector3(aabb.Min.Z * cosY - aabb.Min.X * sinY, aabb.Max.Y, aabb.Min.X * cosY + aabb.Min.Z * sinY) + m_Position; // 5
Vector3 blt = new Vector3(aabb.Min.Z * cosY - aabb.Max.X * sinY, aabb.Max.Y, aabb.Max.X * cosY + aabb.Min.Z * sinY) + m_Position; // 6
Vector3 flt = new Vector3(aabb.Max.Z * cosY - aabb.Max.X * sinY, aabb.Max.Y, aabb.Max.X * cosY + aabb.Max.Z * sinY) + m_Position; // 7
#region WorldToScreen
if (!WorldToScreen(fld, out fld) || !WorldToScreen(brt, out brt)
|| !WorldToScreen(bld, out bld) || !WorldToScreen(frt, out frt)
|| !WorldToScreen(frd, out frd) || !WorldToScreen(brb, out brb)
|| !WorldToScreen(blt, out blt) || !WorldToScreen(flt, out flt))
return;
#endregion
#region DrawLines
DrawLine(fld, brt, color);
DrawLine(brb, blt, color);
DrawLine(fld, brb, color);
DrawLine(brt, blt, color);
DrawLine(frt, bld, color);
DrawLine(frd, flt, color);
DrawLine(frt, frd, color);
DrawLine(bld, flt, color);
DrawLine(frt, fld, color);
DrawLine(frd, brb, color);
DrawLine(brt, bld, color);
DrawLine(blt, flt, color);
#endregion
}
private void DrawMenu(int X, int Y)
{
Color selectedColor
= new Color(255,
214,
0,
255); DrawText
(X, Y,
"F5: ESP Box", ESP_Box
? selectedColor
: Color.
White,
true, fontSmall
); DrawText
(X
+ 100, Y,
"F6: ESP Bone", ESP_Bone
? selectedColor
: Color.
White,
true, fontSmall
); DrawText
(X
+ 200, Y,
"F7: ESP Health", ESP_Health
? selectedColor
: Color.
White,
true, fontSmall
); DrawText
(X
+ 310, Y,
"F8: ESP Distance", ESP_Distance
? selectedColor
: Color.
White,
true, fontSmall
); DrawText
(X
+ 430, Y,
"F9: ESP Vehicle", ESP_Vehicle
? selectedColor
: Color.
White,
true, fontSmall
); }
private void DrawWarn(int X, int Y, int W, int H)
{
RoundedRectangle rect = new RoundedRectangle();
rect.RadiusX = 4;
rect.RadiusY = 4;
rect.Rect = new RectangleF(X, Y, W, H);
solidColorBrush.
Color = new Color(196,
26,
31,
210); device.FillRoundedRectangle(ref rect, solidColorBrush);
DrawText
(X
+ 20, Y
+ 5,
"Spectator on the server.",
Color.
White,
true); DrawText
(X
+ 20, Y
+ 25,
"Watching You!",
Color.
White,
true); }
#endregion
}
}
Ly8vLy8vLy8vLy8vL1hUUkVNRSBIQUNLLy8vLy8vLy8vLy8vLy8vLwovLy8vLy8vLy8vL3Vua25vd25jaGVhdHMubWUvLy8vLy8vLy8vLy8vCgp1c2luZyBTeXN0ZW07CnVzaW5nIFN5c3RlbS5EYXRhOwp1c2luZyBTeXN0ZW0uTGlucTsKdXNpbmcgU3lzdGVtLlRleHQ7CnVzaW5nIFN5c3RlbS5UaHJlYWRpbmc7CnVzaW5nIFN5c3RlbS5EaWFnbm9zdGljczsKdXNpbmcgU3lzdGVtLldpbmRvd3MuRm9ybXM7CnVzaW5nIFN5c3RlbS5Db21wb25lbnRNb2RlbDsKdXNpbmcgU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWM7Cgp1c2luZyBGYWN0b3J5ID0gU2hhcnBEWC5EaXJlY3QyRDEuRmFjdG9yeTsKdXNpbmcgRm9udEZhY3RvcnkgPSBTaGFycERYLkRpcmVjdFdyaXRlLkZhY3Rvcnk7CnVzaW5nIEZvcm1hdCA9IFNoYXJwRFguRFhHSS5Gb3JtYXQ7Cgp1c2luZyBTaGFycERYOwp1c2luZyBTaGFycERYLldpbmRvd3M7CnVzaW5nIFNoYXJwRFguRGlyZWN0MkQxOwp1c2luZyBTaGFycERYLkRpcmVjdFdyaXRlOwp1c2luZyBTeXN0ZW0uUnVudGltZS5JbnRlcm9wU2VydmljZXM7CgpuYW1lc3BhY2UgRXh0ZXJuYWxfRVNQX0Jhc2UKewogICAgcHVibGljIHBhcnRpYWwgY2xhc3MgT3ZlcmxheSA6IEZvcm0KICAgIHsKICAgICAgICAvLyBQcm9jZXNzCiAgICAgICAgcHJpdmF0ZSBQcm9jZXNzIHByb2Nlc3MgPSBudWxsOwogICAgICAgIHByaXZhdGUgVGhyZWFkIHVwZGF0ZVN0cmVhbSA9IG51bGwsIHdpbmRvd1N0cmVhbSA9IG51bGw7CgogICAgICAgIC8vIEdhbWUgRGF0YQogICAgICAgIHByaXZhdGUgTGlzdDxQbGF5ZXI+IHBsYXllcnMgPSBudWxsOwogICAgICAgIHByaXZhdGUgUGxheWVyIGxvY2FsUGxheWVyID0gbnVsbDsKICAgICAgICBwcml2YXRlIE1hdHJpeCB2aWV3UHJvaiwgbV9WaWV3TWF0cml4SW52ZXJzZTsKICAgICAgICBwcml2YXRlIGludCBzcGVjdGF0b3JDb3VudCA9IDA7CgogICAgICAgIC8vIEtleXMgQ29udHJvbAogICAgICAgIHByaXZhdGUgS2V5c01hbmFnZXIgbWFuYWdlcjsKICAgICAgICAvLyBIYW5kbGUKICAgICAgICBwcml2YXRlIEludFB0ciBoYW5kbGU7CgogICAgICAgIC8vIENvbG9yCiAgICAgICAgcHJpdmF0ZSBDb2xvciBlbmVteUNvbG9yID0gbmV3IENvbG9yKDI1NSwgMCwgMCwgMjAwKSwKICAgICAgICAgICAgZW5lbXlDb2xvclZpc2libGUgPSBuZXcgQ29sb3IoMjU1LCAyNTUsIDAsIDIyMCksCiAgICAgICAgICAgIGVuZW15Q29sb3JWZWhpY2xlID0gbmV3IENvbG9yKDI1NSwgMTI5LCA3MiwgMjAwKSwKICAgICAgICAgICAgZW5lbXlTa2VsZXRvbkNvbG9yID0gbmV3IENvbG9yKDI0NSwgMTE0LCAwLCAyNTUpLAogICAgICAgICAgICBmcmllbmRseUNvbG9yID0gbmV3IENvbG9yKDAsIDI1NSwgMCwgMjAwKSwKICAgICAgICAgICAgZnJpZW5kbHlDb2xvclZlaGljbGUgPSBuZXcgQ29sb3IoNjQsIDE1NCwgMjAwLCAyNTUpLAogICAgICAgICAgICBmcmllbmRTa2VsZXRvbkNvbG9yID0gbmV3IENvbG9yKDQ2LCAyMjgsIDIxMywgMjU1KTsKCiAgICAgICAgLy8gU2V0dGluZ3MKICAgICAgICBwcml2YXRlIGJvb2wgRVNQX0JveCA9IHRydWUsIAogICAgICAgICAgICBFU1BfQm9uZSA9IHRydWUsCiAgICAgICAgICAgIEVTUF9IZWFsdGggPSBmYWxzZSwKICAgICAgICAgICAgRVNQX0Rpc3RhbmNlID0gZmFsc2UsCiAgICAgICAgICAgIEVTUF9WZWhpY2xlID0gdHJ1ZTsKCiAgICAgICAgLy8gU2hhcnBEWAogICAgICAgIHByaXZhdGUgV2luZG93UmVuZGVyVGFyZ2V0IGRldmljZTsKICAgICAgICBwcml2YXRlIEh3bmRSZW5kZXJUYXJnZXRQcm9wZXJ0aWVzIHJlbmRlclByb3BlcnRpZXM7CiAgICAgICAgcHJpdmF0ZSBTb2xpZENvbG9yQnJ1c2ggc29saWRDb2xvckJydXNoOwogICAgICAgIHByaXZhdGUgRmFjdG9yeSBmYWN0b3J5OwogICAgICAgIHByaXZhdGUgYm9vbCBJc1Jlc2l6ZSA9IGZhbHNlOwogICAgICAgIHByaXZhdGUgYm9vbCBJc01pbmltaXplZCA9IGZhbHNlOwoKICAgICAgICAvLyBTaGFycERYIEZvbnQKICAgICAgICBwcml2YXRlIFRleHRGb3JtYXQgZm9udCwgZm9udFNtYWxsOwogICAgICAgIHByaXZhdGUgRm9udEZhY3RvcnkgZm9udEZhY3Rvcnk7CiAgICAgICAgcHJpdmF0ZSBjb25zdCBzdHJpbmcgZm9udEZhbWlseSA9ICJDYWxpYnJpIjsKICAgICAgICBwcml2YXRlIGNvbnN0IGZsb2F0IGZvbnRTaXplID0gMTguMGY7CiAgICAgICAgcHJpdmF0ZSBjb25zdCBmbG9hdCBmb250U2l6ZVNtYWxsID0gMTQuMGY7CgogICAgICAgIC8vIFNjcmVlbiBTaXplCiAgICAgICAgcHJpdmF0ZSBSZWN0YW5nbGUgcmVjdDsKCiAgICAgICAgLy8gSW5pdAogICAgICAgIHB1YmxpYyBPdmVybGF5KFByb2Nlc3MgcHJvY2VzcykKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMucHJvY2VzcyA9IHByb2Nlc3M7CiAgICAgICAgICAgIHRoaXMuaGFuZGxlID0gSGFuZGxlOwoKICAgICAgICAgICAgaW50IGluaXRpYWxTdHlsZSA9IE1hbmFnZWQuR2V0V2luZG93TG9uZyh0aGlzLkhhbmRsZSwgLTIwKTsKICAgICAgICAgICAgTWFuYWdlZC5TZXRXaW5kb3dMb25nKHRoaXMuSGFuZGxlLCAtMjAsIGluaXRpYWxTdHlsZSB8IDB4ODAwMDAgfCAweDIwKTsKCiAgICAgICAgICAgIEludFB0ciBIV05EX1RPUE1PU1QgPSBuZXcgSW50UHRyKC0xKTsKICAgICAgICAgICAgY29uc3QgVUludDMyIFNXUF9OT1NJWkUgPSAweDAwMDE7CiAgICAgICAgICAgIGNvbnN0IFVJbnQzMiBTV1BfTk9NT1ZFID0gMHgwMDAyOwogICAgICAgICAgICBjb25zdCBVSW50MzIgVE9QTU9TVF9GTEFHUyA9IFNXUF9OT01PVkUgfCBTV1BfTk9TSVpFOwoKICAgICAgICAgICAgTWFuYWdlZC5TZXRXaW5kb3dQb3ModGhpcy5IYW5kbGUsIEhXTkRfVE9QTU9TVCwgMCwgMCwgMCwgMCwgVE9QTU9TVF9GTEFHUyk7ICAKICAgICAgICAgICAgT25SZXNpemUobnVsbCk7CgogICAgICAgICAgICBJbml0aWFsaXplQ29tcG9uZW50KCk7CiAgICAgICAgfQoKICAgICAgICAvLyBTZXQgd2luZG93IHN0eWxlCiAgICAgICAgcHJvdGVjdGVkIG92ZXJyaWRlIHZvaWQgT25SZXNpemUoRXZlbnRBcmdzIGUpCiAgICAgICAgewogICAgICAgICAgICBpbnRbXSBtYXJnaW5zID0gbmV3IGludFtdIHsgMCwgMCwgcmVjdC5XaWR0aCwgcmVjdC5IZWlnaHQgfTsKICAgICAgICAgICAgTWFuYWdlZC5Ed21FeHRlbmRGcmFtZUludG9DbGllbnRBcmVhKHRoaXMuSGFuZGxlLCByZWYgbWFyZ2lucyk7CiAgICAgICAgfQoKICAgICAgICAvLyBJTklUCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdXaW5kb3dfTG9hZChvYmplY3Qgc2VuZGVyLCBFdmVudEFyZ3MgZSkKICAgICAgICB7CiAgICAgICAgICAgIHRoaXMuVG9wTW9zdCA9IHRydWU7CiAgICAgICAgICAgIHRoaXMuVmlzaWJsZSA9IHRydWU7CiAgICAgICAgICAgIHRoaXMuRm9ybUJvcmRlclN0eWxlID0gRm9ybUJvcmRlclN0eWxlLk5vbmU7CiAgICAgICAgICAgIC8vdGhpcy5XaW5kb3dTdGF0ZSA9IEZvcm1XaW5kb3dTdGF0ZS5NYXhpbWl6ZWQ7CiAgICAgICAgICAgIHRoaXMuV2lkdGggPSByZWN0LldpZHRoOwogICAgICAgICAgICB0aGlzLkhlaWdodCA9IHJlY3QuSGVpZ2h0OwoKICAgICAgICAgICAgLy8gV2luZG93IG5hbWUKICAgICAgICAgICAgdGhpcy5OYW1lID0gUHJvY2Vzcy5HZXRDdXJyZW50UHJvY2VzcygpLlByb2Nlc3NOYW1lICsgIn5PdmVybGF5IjsKICAgICAgICAgICAgdGhpcy5UZXh0ID0gUHJvY2Vzcy5HZXRDdXJyZW50UHJvY2VzcygpLlByb2Nlc3NOYW1lICsgIn5PdmVybGF5IjsKCiAgICAgICAgICAgIC8vIEluaXQgZmFjdG9yeQogICAgICAgICAgICBmYWN0b3J5ID0gbmV3IEZhY3RvcnkoKTsKICAgICAgICAgICAgZm9udEZhY3RvcnkgPSBuZXcgRm9udEZhY3RvcnkoKTsKCiAgICAgICAgICAgIC8vIFJlbmRlciBzZXR0aW5ncwogICAgICAgICAgICByZW5kZXJQcm9wZXJ0aWVzID0gbmV3IEh3bmRSZW5kZXJUYXJnZXRQcm9wZXJ0aWVzKCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgSHduZCA9IHRoaXMuSGFuZGxlLAogICAgICAgICAgICAgICAgUGl4ZWxTaXplID0gbmV3IFNpemUyKHJlY3QuV2lkdGgsIHJlY3QuSGVpZ2h0KSwKICAgICAgICAgICAgICAgIFByZXNlbnRPcHRpb25zID0gUHJlc2VudE9wdGlvbnMuTm9uZQogICAgICAgICAgICB9OwoKICAgICAgICAgICAgLy8gSW5pdCBkZXZpY2UKICAgICAgICAgICAgZGV2aWNlID0gbmV3IFdpbmRvd1JlbmRlclRhcmdldChmYWN0b3J5LCBuZXcgUmVuZGVyVGFyZ2V0UHJvcGVydGllcyhuZXcgUGl4ZWxGb3JtYXQoRm9ybWF0LkI4RzhSOEE4X1VOb3JtLCBBbHBoYU1vZGUuUHJlbXVsdGlwbGllZCkpLCByZW5kZXJQcm9wZXJ0aWVzKTsKCiAgICAgICAgICAgIC8vIEluaXQgYnJ1c2gKICAgICAgICAgICAgc29saWRDb2xvckJydXNoID0gbmV3IFNvbGlkQ29sb3JCcnVzaChkZXZpY2UsIENvbG9yLldoaXRlKTsKCiAgICAgICAgICAgIC8vIEluaXQgZm9udCdzCiAgICAgICAgICAgIGZvbnQgPSBuZXcgVGV4dEZvcm1hdChmb250RmFjdG9yeSwgZm9udEZhbWlseSwgZm9udFNpemUpOwogICAgICAgICAgICBmb250U21hbGwgPSBuZXcgVGV4dEZvcm1hdChmb250RmFjdG9yeSwgZm9udEZhbWlseSwgZm9udFNpemVTbWFsbCk7CgogICAgICAgICAgICAvLyBPcGVuIHByb2Nlc3MKICAgICAgICAgICAgUlBNLk9wZW5Qcm9jZXNzKHByb2Nlc3MuSWQpOwoKICAgICAgICAgICAgLy8gSW5pdCBwbGF5ZXIgYXJyYXkKICAgICAgICAgICAgcGxheWVycyA9IG5ldyBMaXN0PFBsYXllcj4oKTsKICAgICAgICAgICAgbG9jYWxQbGF5ZXIgPSBuZXcgUGxheWVyKCk7CgogICAgICAgICAgICAvLyBJbml0IHVwZGF0ZSB0aHJlYWQKICAgICAgICAgICAgdXBkYXRlU3RyZWFtID0gbmV3IFRocmVhZChuZXcgUGFyYW1ldGVyaXplZFRocmVhZFN0YXJ0KFVwZGF0ZSkpOwogICAgICAgICAgICB1cGRhdGVTdHJlYW0uU3RhcnQoKTsKCiAgICAgICAgICAgIC8vIEluaXQgd2luZG93IHRocmVhZCAocmVzaXplIC8gcG9zaXRpb24pCiAgICAgICAgICAgIHdpbmRvd1N0cmVhbSA9IG5ldyBUaHJlYWQobmV3IFBhcmFtZXRlcml6ZWRUaHJlYWRTdGFydChTZXRXaW5kb3cpKTsKICAgICAgICAgICAgd2luZG93U3RyZWFtLlN0YXJ0KCk7CgogICAgICAgICAgICAvLyBJbml0IEtleSBMaXN0ZW5lcgogICAgICAgICAgICBtYW5hZ2VyID0gbmV3IEtleXNNYW5hZ2VyKCk7CiAgICAgICAgICAgIG1hbmFnZXIuQWRkS2V5KEtleXMuRjUpOwogICAgICAgICAgICBtYW5hZ2VyLkFkZEtleShLZXlzLkY2KTsKICAgICAgICAgICAgbWFuYWdlci5BZGRLZXkoS2V5cy5GNyk7CiAgICAgICAgICAgIG1hbmFnZXIuQWRkS2V5KEtleXMuRjgpOwogICAgICAgICAgICBtYW5hZ2VyLkFkZEtleShLZXlzLkY5KTsKICAgICAgICAgICAgLy9tYW5hZ2VyLktleVVwRXZlbnQgKz0gbmV3IEtleXNNYW5hZ2VyLktleUhhbmRsZXIoS2V5VXBFdmVudCk7CiAgICAgICAgICAgIG1hbmFnZXIuS2V5RG93bkV2ZW50ICs9IG5ldyBLZXlzTWFuYWdlci5LZXlIYW5kbGVyKEtleURvd25FdmVudCk7CiAgICAgICAgfQoKICAgICAgICAvLyBLZXkgRG93biBFdmVudAogICAgICAgIHByaXZhdGUgdm9pZCBLZXlEb3duRXZlbnQoaW50IGtleUlkLCBzdHJpbmcga2V5TmFtZSkKICAgICAgICB7CiAgICAgICAgICAgIHN3aXRjaCAoKEtleXMpa2V5SWQpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNhc2UgS2V5cy5GNToKICAgICAgICAgICAgICAgICAgICB0aGlzLkVTUF9Cb3ggPSAhdGhpcy5FU1BfQm94OwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBLZXlzLkY2OgogICAgICAgICAgICAgICAgICAgIHRoaXMuRVNQX0JvbmUgPSAhdGhpcy5FU1BfQm9uZTsKICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgS2V5cy5GNzoKICAgICAgICAgICAgICAgICAgICB0aGlzLkVTUF9IZWFsdGggPSAhdGhpcy5FU1BfSGVhbHRoOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBLZXlzLkY4OgogICAgICAgICAgICAgICAgICAgIHRoaXMuRVNQX0Rpc3RhbmNlID0gIXRoaXMuRVNQX0Rpc3RhbmNlOwogICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgY2FzZSBLZXlzLkY5OgogICAgICAgICAgICAgICAgICAgIHRoaXMuRVNQX1ZlaGljbGUgPSAhdGhpcy5FU1BfVmVoaWNsZTsKICAgICAgICAgICAgICAgICAgICBicmVhazsgICAgICAKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgLy8gRlBTIFN0YXRzCiAgICAgICAgcHJpdmF0ZSBzdGF0aWMgaW50IGxhc3RUaWNrOwogICAgICAgIHByaXZhdGUgc3RhdGljIGludCBsYXN0RnJhbWVSYXRlOwogICAgICAgIHByaXZhdGUgc3RhdGljIGludCBmcmFtZVJhdGU7CgogICAgICAgIC8vIENoZWNrIGlzIEdhbWUgUnVuCiAgICAgICAgcHJpdmF0ZSBib29sIElzR2FtZVJ1bigpCiAgICAgICAgewogICAgICAgICAgICBmb3JlYWNoIChQcm9jZXNzIHAgaW4gUHJvY2Vzcy5HZXRQcm9jZXNzZXMoKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaWYgKHAuUHJvY2Vzc05hbWUgPT0gcHJvY2Vzcy5Qcm9jZXNzTmFtZSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgICAgICByZXR1cm4gZmFsc2U7CiAgICAgICAgfSAKCiAgICAgICAgLy8gVXBkYXRlIFRocmVhZAogICAgICAgIHByaXZhdGUgdm9pZCBVcGRhdGUob2JqZWN0IHNlbmRlcikKICAgICAgICB7CiAgICAgICAgICAgIHdoaWxlIChJc0dhbWVSdW4oKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgLy8gUmVzaXplCiAgICAgICAgICAgICAgICBpZiAoSXNSZXNpemUpCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgZGV2aWNlLlJlc2l6ZShuZXcgU2l6ZTIocmVjdC5XaWR0aCwgcmVjdC5IZWlnaHQpKTsKICAgICAgICAgICAgICAgICAgICAvL0NvbnNvbGUuV3JpdGVMaW5lKCJSZXNpemUgezB9L3sxfSIsIHJlY3QuV2lkdGgsIHJlY3QuSGVpZ2h0KTsKICAgICAgICAgICAgICAgICAgICBJc1Jlc2l6ZSA9IGZhbHNlOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIEJlZ2luIERyYXcKICAgICAgICAgICAgICAgIGRldmljZS5CZWdpbkRyYXcoKTsKICAgICAgICAgICAgICAgIGRldmljZS5DbGVhcihuZXcgQ29sb3I0KDAuMGYsIDAuMGYsIDAuMGYsIDAuMGYpKTsKCiAgICAgICAgICAgICAgICAvLyBDaGVjayBXaW5kb3cgU3RhdGUKICAgICAgICAgICAgICAgIGlmICghSXNNaW5pbWl6ZWQpCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgLy8gUmVhZCAmIERyYXcgUGxheWVycwogICAgICAgICAgICAgICAgICAgIFJlYWQoKTsKCiAgICAgICAgICAgICAgICAgICAgLy8gRHJhdyBDcmVkaXRzCiAgICAgICAgICAgICAgICAgICAgRHJhd1RleHRDZW50ZXIocmVjdC5XaWR0aCAvIDIgLSAxMjUsIDUsIDI1MCwgKGludClmb250LkZvbnRTaXplLCAiRVhURVJOQUwgRVNQIEJBU0UgQlkgWFRSRU1FMjAxMCIsIG5ldyBDb2xvcigyNTUsIDIxNCwgMCwgMjU1KSwgdHJ1ZSk7CgogICAgICAgICAgICAgICAgICAgIC8vIERyYXcgU3BlY3RhdG9yIENvdW50CiAgICAgICAgICAgICAgICAgICAgRHJhd1RleHRDZW50ZXIocmVjdC5XaWR0aCAvIDIgLSAxMDAsIHJlY3QuSGVpZ2h0IC0gKGludClmb250LkZvbnRTaXplLCAyMDAsIChpbnQpZm9udC5Gb250U2l6ZSwgc3BlY3RhdG9yQ291bnQgKyAiIFNQRUNUQVRPUihTKSBPTiBBIFNFUlZFUiIsIG5ldyBDb2xvcigyNTUsIDIxNCwgMCwgMjU1KSwgdHJ1ZSk7CgogICAgICAgICAgICAgICAgICAgIC8vIERyYXcgTWVudQogICAgICAgICAgICAgICAgICAgIERyYXdNZW51KDUsIDUpOwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIC8vIEVuZCBEcmF3CiAgICAgICAgICAgICAgICBkZXZpY2UuRW5kRHJhdygpOwogICAgICAgICAgICAgICAgQ2FsY3VsYXRlRnJhbWVSYXRlKCk7CiAgICAgICAgICAgICAgICAvL1RocmVhZC5TbGVlcChJbnRlcnZhbCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIC8vIENsb3NlIFByb2Nlc3MKICAgICAgICAgICAgUlBNLkNsb3NlUHJvY2VzcygpOwogICAgICAgICAgICAvLyBFeGl0CiAgICAgICAgICAgIEVudmlyb25tZW50LkV4aXQoMCk7CiAgICAgICAgfQoKICAgICAgICAvLyBSZWFkIEdhbWUgTWVtb3JyeQogICAgICAgIHByaXZhdGUgdm9pZCBSZWFkKCkKICAgICAgICB7CiAgICAgICAgICAgIC8vIFJlc2V0IE9sZCBEYXRhCiAgICAgICAgICAgIHBsYXllcnMuQ2xlYXIoKTsKICAgICAgICAgICAgbG9jYWxQbGF5ZXIgPSBuZXcgUGxheWVyKCk7CgogICAgICAgICAgICAvLyBSZWFkIExvY2FsCiAgICAgICAgICAgICNyZWdpb24gR2V0IExvY2FsIFBsYXllcgogICAgICAgICAgICBJbnQ2NCBwR0NvbnRleHQgPSBSUE0uUmVhZDxJbnQ2ND4oT2Zmc2V0cy5DbGllbnRHYW1lQ29udGV4dC5HZXRJbnN0YW5jZSgpKTsKICAgICAgICAgICAgaWYgKCFSUE0uSXNWYWxpZChwR0NvbnRleHQpKQogICAgICAgICAgICAgICAgcmV0dXJuOwoKICAgICAgICAgICAgSW50NjQgcFBsYXllck1hbmFnZXIgPSBSUE0uUmVhZDxJbnQ2ND4ocEdDb250ZXh0ICsgT2Zmc2V0cy5DbGllbnRHYW1lQ29udGV4dC5tX3BQbGF5ZXJNYW5hZ2VyKTsKICAgICAgICAgICAgaWYgKCFSUE0uSXNWYWxpZChwUGxheWVyTWFuYWdlcikpCiAgICAgICAgICAgICAgICByZXR1cm47CgogICAgICAgICAgICBJbnQ2NCBwTG9jYWxQbGF5ZXIgPSBSUE0uUmVhZDxJbnQ2ND4ocFBsYXllck1hbmFnZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllck1hbmFnZXIubV9wTG9jYWxQbGF5ZXIpOwogICAgICAgICAgICBpZiAoIVJQTS5Jc1ZhbGlkKHBMb2NhbFBsYXllcikpCiAgICAgICAgICAgICAgICByZXR1cm47CgogICAgICAgICAgICAvL1JQTS5SZWFkPEludDY0PihwTG9jYWxQbGF5ZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllci5tX3BDb250cm9sbGVkQ29udHJvbGxhYmxlKTsKICAgICAgICAgICAgSW50NjQgcExvY2FsU29sZGllciA9IEdldENsaWVudFNvbGRpZXJFbnRpdHkocExvY2FsUGxheWVyLCBsb2NhbFBsYXllcik7CiAgICAgICAgICAgIGlmICghUlBNLklzVmFsaWQocExvY2FsU29sZGllcikpCiAgICAgICAgICAgICAgICByZXR1cm47CgogICAgICAgICAgICBJbnQ2NCBwSGVhbHRoQ29tcG9uZW50ID0gUlBNLlJlYWQ8SW50NjQ+KHBMb2NhbFNvbGRpZXIgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJFbnRpdHkubV9wSGVhbHRoQ29tcG9uZW50KTsKICAgICAgICAgICAgaWYgKCFSUE0uSXNWYWxpZChwSGVhbHRoQ29tcG9uZW50KSkKICAgICAgICAgICAgICAgIHJldHVybjsKCiAgICAgICAgICAgIEludDY0IG1fcFByZWRpY3RlZENvbnRyb2xsZXIgPSBSUE0uUmVhZDxJbnQ2ND4ocExvY2FsU29sZGllciArIE9mZnNldHMuQ2xpZW50U29sZGllckVudGl0eS5tX3BQcmVkaWN0ZWRDb250cm9sbGVyKTsKICAgICAgICAgICAgaWYgKCFSUE0uSXNWYWxpZChtX3BQcmVkaWN0ZWRDb250cm9sbGVyKSkKICAgICAgICAgICAgICAgIHJldHVybjsKCiAgICAgICAgICAgIC8vIEhlYWx0aAogICAgICAgICAgICBsb2NhbFBsYXllci5IZWFsdGggPSBSUE0uUmVhZDxmbG9hdD4ocEhlYWx0aENvbXBvbmVudCArIE9mZnNldHMuSGVhbHRoQ29tcG9uZW50Lm1fSGVhbHRoKTsKICAgICAgICAgICAgbG9jYWxQbGF5ZXIuTWF4SGVhbHRoID0gUlBNLlJlYWQ8ZmxvYXQ+KHBIZWFsdGhDb21wb25lbnQgKyBPZmZzZXRzLkhlYWx0aENvbXBvbmVudC5tX01heEhlYWx0aCk7CgogICAgICAgICAgICBpZiAobG9jYWxQbGF5ZXIuSGVhbHRoIDw9IDAuMWYpIC8vIFlPVSBERUFEIDpECiAgICAgICAgICAgICAgICByZXR1cm47CgogICAgICAgICAgICAvLyBPcmlnaW4KICAgICAgICAgICAgbG9jYWxQbGF5ZXIuT3JpZ2luID0gUlBNLlJlYWQ8VmVjdG9yMz4obV9wUHJlZGljdGVkQ29udHJvbGxlciArIE9mZnNldHMuQ2xpZW50U29sZGllclByZWRpY3Rpb24ubV9Qb3NpdGlvbik7CgogICAgICAgICAgICAvLyBPdGhlcgogICAgICAgICAgICBsb2NhbFBsYXllci5UZWFtID0gUlBNLlJlYWQ8SW50MzI+KHBMb2NhbFBsYXllciArIE9mZnNldHMuQ2xpZW50UGxheWVyLm1fdGVhbUlkKTsKICAgICAgICAgICAgLy9sb2NhbFBsYXllci5OYW1lID0gUlBNLlJlYWRTdHJpbmcocExvY2FsUGxheWVyICsgT2Zmc2V0cy5DbGllbnRQbGF5ZXIuc3pOYW1lLCAxMCk7CiAgICAgICAgICAgIGxvY2FsUGxheWVyLlBvc2UgPSBSUE0uUmVhZDxJbnQzMj4ocExvY2FsU29sZGllciArIE9mZnNldHMuQ2xpZW50U29sZGllckVudGl0eS5tX3Bvc2VUeXBlKTsKICAgICAgICAgICAgbG9jYWxQbGF5ZXIuWWF3ID0gUlBNLlJlYWQ8ZmxvYXQ+KHBMb2NhbFNvbGRpZXIgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJFbnRpdHkubV9hdXRob3JhdGl2ZVlhdyk7CiAgICAgICAgICAgIGxvY2FsUGxheWVyLklzT2NjbHVkZWQgPSBSUE0uUmVhZDxCeXRlPihwTG9jYWxTb2xkaWVyICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fb2NjbHVkZWQpOwoKICAgICAgICAgICAgLy8gV2VhcG9uIEFtbW8KICAgICAgICAgICAgaWYgKGxvY2FsUGxheWVyLkluVmVoaWNsZSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgSW50NjQgcEN1cnJlbnRXZWFwb25GaXJpbmcgPSBSUE0uUmVhZDxJbnQ2ND4oT2Zmc2V0cy5PRkZTRVRfQ1VSUkVOVF9XRUFQT05GSVJJTkcpOwogICAgICAgICAgICAgICAgaWYgKFJQTS5Jc1ZhbGlkKHBDdXJyZW50V2VhcG9uRmlyaW5nKSkKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAvLyBBbW1vCiAgICAgICAgICAgICAgICAgICAgbG9jYWxQbGF5ZXIuQW1tbyA9IFJQTS5SZWFkPEludDMyPihwQ3VycmVudFdlYXBvbkZpcmluZyArIE9mZnNldHMuV2VhcG9uRmlyaW5nLm1fcHJvamVjdGlsZXNMb2FkZWQpOwogICAgICAgICAgICAgICAgICAgIGxvY2FsUGxheWVyLkFtbW9DbGlwID0gUlBNLlJlYWQ8SW50MzI+KHBDdXJyZW50V2VhcG9uRmlyaW5nICsgT2Zmc2V0cy5XZWFwb25GaXJpbmcubV9wcm9qZWN0aWxlc0luTWFnYXppbmVzKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICBlbHNlCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIEludDY0IHBDbGllbnRXZWFwb25Db21wb25lbnQgPSBSUE0uUmVhZDxJbnQ2ND4ocExvY2FsU29sZGllciArIE9mZnNldHMuQ2xpZW50U29sZGllckVudGl0eS5tX3NvbGRpZXJXZWFwb25zQ29tcG9uZW50KTsKICAgICAgICAgICAgICAgIGlmIChSUE0uSXNWYWxpZChwQ2xpZW50V2VhcG9uQ29tcG9uZW50KSkKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBJbnQ2NCBwV2VhcG9uSGFuZGxlID0gUlBNLlJlYWQ8SW50NjQ+KHBDbGllbnRXZWFwb25Db21wb25lbnQgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJXZWFwb25zQ29tcG9uZW50Lm1faGFuZGxlcik7CiAgICAgICAgICAgICAgICAgICAgSW50MzIgQWN0aXZlU2xvdCA9IFJQTS5SZWFkPEludDMyPihwQ2xpZW50V2VhcG9uQ29tcG9uZW50ICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyV2VhcG9uc0NvbXBvbmVudC5tX2FjdGl2ZVNsb3QpOwoKICAgICAgICAgICAgICAgICAgICBpZiAoUlBNLklzVmFsaWQocFdlYXBvbkhhbmRsZSkpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBJbnQ2NCBwU29sZGllcldlYXBvbiA9IFJQTS5SZWFkPEludDY0PihwV2VhcG9uSGFuZGxlICsgQWN0aXZlU2xvdCAqIDB4OCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChSUE0uSXNWYWxpZChwU29sZGllcldlYXBvbikpCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IHBDb3JyZWN0ZWRGaXJpbmcgPSBSUE0uUmVhZDxJbnQ2ND4ocFNvbGRpZXJXZWFwb24gKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJXZWFwb24ubV9wUHJpbWFyeSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoUlBNLklzVmFsaWQocENvcnJlY3RlZEZpcmluZykpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQW1tbwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsUGxheWVyLkFtbW8gPSBSUE0uUmVhZDxJbnQzMj4ocENvcnJlY3RlZEZpcmluZyArIE9mZnNldHMuV2VhcG9uRmlyaW5nLm1fcHJvamVjdGlsZXNMb2FkZWQpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsUGxheWVyLkFtbW9DbGlwID0gUlBNLlJlYWQ8SW50MzI+KHBDb3JyZWN0ZWRGaXJpbmcgKyBPZmZzZXRzLldlYXBvbkZpcmluZy5tX3Byb2plY3RpbGVzSW5NYWdhemluZXMpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9ICAKICAgICAgICAgICAgI2VuZHJlZ2lvbgoKICAgICAgICAgICAgLy8gUmVuZGVyIFZpZXcKICAgICAgICAgICAgSW50NjQgcEdhbWVSZW5kZXJlciA9IFJQTS5SZWFkPEludDY0PihPZmZzZXRzLkdhbWVSZW5kZXJlci5HZXRJbnN0YW5jZSgpKTsKICAgICAgICAgICAgSW50NjQgcFJlbmRlclZpZXcgPSBSUE0uUmVhZDxJbnQ2ND4ocEdhbWVSZW5kZXJlciArIE9mZnNldHMuR2FtZVJlbmRlcmVyLm1fcFJlbmRlclZpZXcpOwoKICAgICAgICAgICAgLy8gUmVhZCBTY3JlZW4gTWF0cml4CiAgICAgICAgICAgIHZpZXdQcm9qID0gUlBNLlJlYWQ8TWF0cml4PihwUmVuZGVyVmlldyArIE9mZnNldHMuUmVuZGVyVmlldy5tX1ZpZXdQcm9qKTsKICAgICAgICAgICAgbV9WaWV3TWF0cml4SW52ZXJzZSA9IFJQTS5SZWFkPE1hdHJpeD4ocFJlbmRlclZpZXcgKyBPZmZzZXRzLlJlbmRlclZpZXcubV9WaWV3TWF0cml4SW52ZXJzZSk7CgogICAgICAgICAgICAvLyBQb2ludGVyIHRvIFBsYXllcnMgQXJyYXkKICAgICAgICAgICAgSW50NjQgbV9wcFBsYXllciA9IFJQTS5SZWFkPEludDY0PihwUGxheWVyTWFuYWdlciArIE9mZnNldHMuQ2xpZW50UGxheWVyTWFuYWdlci5tX3BwUGxheWVyKTsKICAgICAgICAgICAgaWYgKCFSUE0uSXNWYWxpZChtX3BwUGxheWVyKSkKICAgICAgICAgICAgICAgIHJldHVybjsKCiAgICAgICAgICAgIC8vIFJlc2V0CiAgICAgICAgICAgIHNwZWN0YXRvckNvdW50ID0gMDsKCiAgICAgICAgICAgIC8vIEdldCBQbGF5ZXIgYnkgSWQKICAgICAgICAgICAgI3JlZ2lvbiBHZXQgUGxheWVyIGJ5IElkCiAgICAgICAgICAgIGZvciAodWludCBpID0gMDsgaSA8IDcwOyBpKyspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBuZXcgUGxheWVyCiAgICAgICAgICAgICAgICBQbGF5ZXIgcGxheWVyID0gbmV3IFBsYXllcigpOwoKICAgICAgICAgICAgICAgIC8vIFBvaW50ZXIgdG8gQ2xpZW50UGxheWVyIGNsYXNzIChQbGF5ZXIgQXJyYXkgKyAoSWQgKiBTaXplIG9mIFBvaW50ZXIpKQogICAgICAgICAgICAgICAgSW50NjQgcEVuZW15UGxheWVyID0gUlBNLlJlYWQ8SW50NjQ+KG1fcHBQbGF5ZXIgKyAoaSAqIHNpemVvZihJbnQ2NCkpKTsKICAgICAgICAgICAgICAgIGlmICghUlBNLklzVmFsaWQocEVuZW15UGxheWVyKSkKICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKCiAgICAgICAgICAgICAgICAvL2lmIChwRW5lbXlQbGF5ZXIgPT0gcExvY2FsUGxheWVyKQogICAgICAgICAgICAgICAgLy8gICAgY29udGludWU7CgogICAgICAgICAgICAgICAgcGxheWVyLklzU3BlY3RhdG9yID0gQ29udmVydC5Ub0Jvb2xlYW4oUlBNLlJlYWQ8Qnl0ZT4ocEVuZW15UGxheWVyICsgT2Zmc2V0cy5DbGllbnRQbGF5ZXIubV9pc1NwZWN0YXRvcikpOwoKICAgICAgICAgICAgICAgIGlmIChwbGF5ZXIuSXNTcGVjdGF0b3IpCiAgICAgICAgICAgICAgICAgICAgc3BlY3RhdG9yQ291bnQrKzsKCiAgICAgICAgICAgICAgICAvLyBOYW1lCiAgICAgICAgICAgICAgICBwbGF5ZXIuTmFtZSA9IFJQTS5SZWFkU3RyaW5nKHBFbmVteVBsYXllciArIE9mZnNldHMuQ2xpZW50UGxheWVyLnN6TmFtZSwgMTApOwoKICAgICAgICAgICAgICAgIC8vIFJQTS5SZWFkPEludDY0PihwRW5lbXlQbGF5ZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllci5tX3BDb250cm9sbGVkQ29udHJvbGxhYmxlKTsKICAgICAgICAgICAgICAgIEludDY0IHBFbmVteVNvbGRpZXIgPSBHZXRDbGllbnRTb2xkaWVyRW50aXR5KHBFbmVteVBsYXllciwgcGxheWVyKTsKICAgICAgICAgICAgICAgIGlmICghUlBNLklzVmFsaWQocEVuZW15U29sZGllcikpCiAgICAgICAgICAgICAgICAgICAgY29udGludWU7CgogICAgICAgICAgICAgICAgSW50NjQgcEVuZW15SGVhbHRoQ29tcG9uZW50ID0gUlBNLlJlYWQ8SW50NjQ+KHBFbmVteVNvbGRpZXIgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJFbnRpdHkubV9wSGVhbHRoQ29tcG9uZW50KTsKICAgICAgICAgICAgICAgIGlmICghUlBNLklzVmFsaWQocEVuZW15SGVhbHRoQ29tcG9uZW50KSkKICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKCiAgICAgICAgICAgICAgICBJbnQ2NCBwRW5lbXlQcmVkaWN0ZWRDb250cm9sbGVyID0gUlBNLlJlYWQ8SW50NjQ+KHBFbmVteVNvbGRpZXIgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJFbnRpdHkubV9wUHJlZGljdGVkQ29udHJvbGxlcik7CiAgICAgICAgICAgICAgICBpZiAoIVJQTS5Jc1ZhbGlkKHBFbmVteVByZWRpY3RlZENvbnRyb2xsZXIpKQogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwogICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAvLyBIZWFsdGgKICAgICAgICAgICAgICAgIHBsYXllci5IZWFsdGggPSBSUE0uUmVhZDxmbG9hdD4ocEVuZW15SGVhbHRoQ29tcG9uZW50ICsgT2Zmc2V0cy5IZWFsdGhDb21wb25lbnQubV9IZWFsdGgpOwogICAgICAgICAgICAgICAgcGxheWVyLk1heEhlYWx0aCA9IFJQTS5SZWFkPGZsb2F0PihwRW5lbXlIZWFsdGhDb21wb25lbnQgKyBPZmZzZXRzLkhlYWx0aENvbXBvbmVudC5tX01heEhlYWx0aCk7CgogICAgICAgICAgICAgICAgaWYgKHBsYXllci5IZWFsdGggPD0gMC4xZikgLy8gREVBRAogICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlOwoKICAgICAgICAgICAgICAgIC8vIE9yaWdpbiAoUG9zaXRpb24gaW4gR2FtZSBYLCBZLCBaKQogICAgICAgICAgICAgICAgcGxheWVyLk9yaWdpbiA9IFJQTS5SZWFkPFZlY3RvcjM+KHBFbmVteVByZWRpY3RlZENvbnRyb2xsZXIgKyBPZmZzZXRzLkNsaWVudFNvbGRpZXJQcmVkaWN0aW9uLm1fUG9zaXRpb24pOwoKICAgICAgICAgICAgICAgIC8vIE90aGVyCiAgICAgICAgICAgICAgICBwbGF5ZXIuVGVhbSA9IFJQTS5SZWFkPEludDMyPihwRW5lbXlQbGF5ZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllci5tX3RlYW1JZCk7CiAgICAgICAgICAgICAgICBwbGF5ZXIuUG9zZSA9IFJQTS5SZWFkPEludDMyPihwRW5lbXlTb2xkaWVyICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fcG9zZVR5cGUpOwogICAgICAgICAgICAgICAgcGxheWVyLllhdyA9IFJQTS5SZWFkPGZsb2F0PihwRW5lbXlTb2xkaWVyICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fYXV0aG9yYXRpdmVZYXcpOwogICAgICAgICAgICAgICAgcGxheWVyLklzT2NjbHVkZWQgPSBSUE0uUmVhZDxCeXRlPihwRW5lbXlTb2xkaWVyICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fb2NjbHVkZWQpOwoKICAgICAgICAgICAgICAgIC8vIERpc3RhbmNlIHRvIFlvdQogICAgICAgICAgICAgICAgcGxheWVyLkRpc3RhbmNlID0gVmVjdG9yMy5EaXN0YW5jZShsb2NhbFBsYXllci5PcmlnaW4sIHBsYXllci5PcmlnaW4pOwoKICAgICAgICAgICAgICAgIGlmIChwbGF5ZXIuSXNWYWxpZCgpKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICNyZWdpb24gQm9uZSBFU1AKICAgICAgICAgICAgICAgICAgICBpZiAoRVNQX0JvbmUpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBQbGF5ZXIgQm9uZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoR2V0Qm9ueUJ5SWQocEVuZW15U29sZGllciwgKGludClPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLkJPTkVTLkJPTkVfSEVBRCwgb3V0IHBsYXllci5Cb25lLkJPTkVfSEVBRCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX0xFRlRFTEJPV1JPTEwsIG91dCBwbGF5ZXIuQm9uZS5CT05FX0xFRlRFTEJPV1JPTEwpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBHZXRCb255QnlJZChwRW5lbXlTb2xkaWVyLCAoaW50KU9mZnNldHMuVXBkYXRlUG9zZVJlc3VsdERhdGEuQk9ORVMuQk9ORV9MRUZURk9PVCwgb3V0IHBsYXllci5Cb25lLkJPTkVfTEVGVEZPT1QpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBHZXRCb255QnlJZChwRW5lbXlTb2xkaWVyLCAoaW50KU9mZnNldHMuVXBkYXRlUG9zZVJlc3VsdERhdGEuQk9ORVMuQk9ORV9MRUZUSEFORCwgb3V0IHBsYXllci5Cb25lLkJPTkVfTEVGVEhBTkQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBHZXRCb255QnlJZChwRW5lbXlTb2xkaWVyLCAoaW50KU9mZnNldHMuVXBkYXRlUG9zZVJlc3VsdERhdGEuQk9ORVMuQk9ORV9MRUZUS05FRVJPTEwsIG91dCBwbGF5ZXIuQm9uZS5CT05FX0xFRlRLTkVFUk9MTCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX0xFRlRTSE9VTERFUiwgb3V0IHBsYXllci5Cb25lLkJPTkVfTEVGVFNIT1VMREVSKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgR2V0Qm9ueUJ5SWQocEVuZW15U29sZGllciwgKGludClPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLkJPTkVTLkJPTkVfTkVDSywgb3V0IHBsYXllci5Cb25lLkJPTkVfTkVDSykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX1JJR0hURUxCT1dST0xMLCBvdXQgcGxheWVyLkJvbmUuQk9ORV9SSUdIVEVMQk9XUk9MTCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX1JJR0hURk9PVCwgb3V0IHBsYXllci5Cb25lLkJPTkVfUklHSFRGT09UKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgR2V0Qm9ueUJ5SWQocEVuZW15U29sZGllciwgKGludClPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLkJPTkVTLkJPTkVfUklHSFRIQU5ELCBvdXQgcGxheWVyLkJvbmUuQk9ORV9SSUdIVEhBTkQpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAmJiBHZXRCb255QnlJZChwRW5lbXlTb2xkaWVyLCAoaW50KU9mZnNldHMuVXBkYXRlUG9zZVJlc3VsdERhdGEuQk9ORVMuQk9ORV9SSUdIVEtORUVST0xMLCBvdXQgcGxheWVyLkJvbmUuQk9ORV9SSUdIVEtORUVST0xMKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgR2V0Qm9ueUJ5SWQocEVuZW15U29sZGllciwgKGludClPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLkJPTkVTLkJPTkVfUklHSFRTSE9VTERFUiwgb3V0IHBsYXllci5Cb25lLkJPTkVfUklHSFRTSE9VTERFUikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX1NQSU5FLCBvdXQgcGxheWVyLkJvbmUuQk9ORV9TUElORSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIEdldEJvbnlCeUlkKHBFbmVteVNvbGRpZXIsIChpbnQpT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5CT05FUy5CT05FX1NQSU5FMSwgb3V0IHBsYXllci5Cb25lLkJPTkVfU1BJTkUxKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgR2V0Qm9ueUJ5SWQocEVuZW15U29sZGllciwgKGludClPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLkJPTkVTLkJPTkVfU1BJTkUyLCBvdXQgcGxheWVyLkJvbmUuQk9ORV9TUElORTIpKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEcmF3Qm9uZShwbGF5ZXIpOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICNlbmRyZWdpb24KCiAgICAgICAgICAgICAgICAgICAgVmVjdG9yMyB3MnNGb290LCB3MnNIZWFkOwogICAgICAgICAgICAgICAgICAgIGlmIChXb3JsZFRvU2NyZWVuKHBsYXllci5PcmlnaW4sIG91dCB3MnNGb290KSAmJgogICAgICAgICAgICAgICAgICAgICAgICBXb3JsZFRvU2NyZWVuKHBsYXllci5PcmlnaW4sIHBsYXllci5Qb3NlLCBvdXQgdzJzSGVhZCkpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICBmbG9hdCBIID0gdzJzRm9vdC5ZIC0gdzJzSGVhZC5ZOwogICAgICAgICAgICAgICAgICAgICAgICBmbG9hdCBXID0gSCAvIDI7CiAgICAgICAgICAgICAgICAgICAgICAgIGZsb2F0IFggPSB3MnNIZWFkLlggLSBXIC8gMjsKCiAgICAgICAgICAgICAgICAgICAgICAgICNyZWdpb24gRVNQIENvbG9yCiAgICAgICAgICAgICAgICAgICAgICAgIENvbG9yIGNvbG9yOwogICAgICAgICAgICAgICAgICAgICAgICBpZiAocGxheWVyLlRlYW0gPT0gbG9jYWxQbGF5ZXIuVGVhbSkgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZnJpZW5kbHlDb2xvcjsKICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gcGxheWVyLklzVmlzaWJsZSgpID8gZW5lbXlDb2xvclZpc2libGUgOiBlbmVteUNvbG9yOwogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICNlbmRyZWdpb24KCiAgICAgICAgICAgICAgICAgICAgICAgICNyZWdpb24gRHJhdyBFU1AKICAgICAgICAgICAgICAgICAgICAgICAgLy8gRVNQIEJveAogICAgICAgICAgICAgICAgICAgICAgICBpZiAoRVNQX0JveCkKICAgICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgRHJhd0FBQkIocGxheWVyLkdldEFBQkIoKSwgcGxheWVyLk9yaWdpbiwgcGxheWVyLllhdywgY29sb3IpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9EcmF3UmVjdCgoaW50KVgsIChpbnQpSGVhZC5ZLCAoaW50KUJveFdpZHRoLCAoaW50KUhlYWRUb0Zvb3QsIGNvbG9yKTsKICAgICAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAgICAgLy8gRVNQIFZlaGljbGUKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKEVTUF9WZWhpY2xlKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEcmF3QUFCQihwbGF5ZXIuVmVoaWNsZUFBQkIsIHBsYXllci5WZWhpY2xlVHJhbmZzb3JtLCBwbGF5ZXIuVGVhbSA9PSBsb2NhbFBsYXllci5UZWFtID8gZnJpZW5kbHlDb2xvclZlaGljbGUgOiBlbmVteUNvbG9yVmVoaWNsZSk7CiAgICAgICAgICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEVTUCBEaXN0YW5jZQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoRVNQX0Rpc3RhbmNlKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEcmF3VGV4dCgoaW50KVgsIChpbnQpdzJzRm9vdC5ZLCAoaW50KXBsYXllci5EaXN0YW5jZSArICJtIiwgQ29sb3IuV2hpdGUsIHRydWUpOwogICAgICAgICAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgICAgICAgICAvLyBFU1AgSGVhbHRoCiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChFU1BfSGVhbHRoKQogICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEcmF3SGVhbHRoKChpbnQpWCwgKGludCl3MnNIZWFkLlkgLSA2LCAoaW50KVcsIDMsIChpbnQpcGxheWVyLkhlYWx0aCwgKGludClwbGF5ZXIuTWF4SGVhbHRoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBWZWhpY2xlIEhlYWx0aAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBsYXllci5JblZlaGljbGUgJiYgcGxheWVyLklzRHJpdmVyKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERyYXdIZWFsdGgoKGludClYLCAoaW50KXcyc0hlYWQuWSAtIDEwLCAoaW50KVcsIDMsIChpbnQpcGxheWVyLlZlaGljbGVIZWFsdGgsIChpbnQpcGxheWVyLlZlaGljbGVNYXhIZWFsdGgpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICNlbmRyZWdpb24KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CgogICAgICAgICAgICAgICAgLy8gQUREIElOIEFSUkFZCiAgICAgICAgICAgICAgICBwbGF5ZXJzLkFkZChwbGF5ZXIpOwogICAgICAgICAgICB9IAogICAgICAgICAgICAjZW5kcmVnaW9uCgogICAgICAgICAgICAvLyBDaGVjayBTcGVjdGF0b3IgQ291bnQKICAgICAgICAgICAgaWYgKHNwZWN0YXRvckNvdW50ID4gMCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgRHJhd1dhcm4ocmVjdC5DZW50ZXIuWCAtIDEyNSwgMjUsIDI1MCwgNTUpOwogICAgICAgICAgICB9CiAgICAgICAgfQoKICAgICAgICAvLyBHZXQgU29sZGllckVudGl0eQogICAgICAgIHByaXZhdGUgSW50NjQgR2V0Q2xpZW50U29sZGllckVudGl0eShJbnQ2NCBwQ2xpZW50UGxheWVyLCBQbGF5ZXIgcGxheWVyKQogICAgICAgIHsKICAgICAgICAgICAgSW50NjQgcEF0dGFjaGVkID0gUlBNLlJlYWQ8SW50NjQ+KHBDbGllbnRQbGF5ZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllci5tX3BBdHRhY2hlZENvbnRyb2xsYWJsZSk7CiAgICAgICAgICAgIGlmIChSUE0uSXNWYWxpZChwQXR0YWNoZWQpKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBJbnQ2NCBtX0NsaWVudFNvbGRpZXIgPSBSUE0uUmVhZDxJbnQ2ND4oUlBNLlJlYWQ8SW50NjQ+KHBDbGllbnRQbGF5ZXIgKyBPZmZzZXRzLkNsaWVudFBsYXllci5tX2NoYXJhY3RlcikpIC0gc2l6ZW9mKEludDY0KTsKICAgICAgICAgICAgICAgIGlmIChSUE0uSXNWYWxpZChtX0NsaWVudFNvbGRpZXIpKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIHBsYXllci5JblZlaGljbGUgPSB0cnVlOwoKICAgICAgICAgICAgICAgICAgICBJbnQ2NCBwVmVoaWNsZUVudGl0eSA9IFJQTS5SZWFkPEludDY0PihwQ2xpZW50UGxheWVyICsgT2Zmc2V0cy5DbGllbnRQbGF5ZXIubV9wQXR0YWNoZWRDb250cm9sbGFibGUpOwogICAgICAgICAgICAgICAgICAgIGlmIChSUE0uSXNWYWxpZChwVmVoaWNsZUVudGl0eSkpCiAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAvLyBEcml2ZXIKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFJQTS5SZWFkPEludDMyPihwQ2xpZW50UGxheWVyICsgT2Zmc2V0cy5DbGllbnRQbGF5ZXIubV9hdHRhY2hlZEVudHJ5SWQpID09IDApCiAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFZlaGljbGUgQUFCQgogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKEVTUF9WZWhpY2xlKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IHBEeW5hbWljUGh5c2ljc0VudGl0eSA9IFJQTS5SZWFkPEludDY0PihwVmVoaWNsZUVudGl0eSArIE9mZnNldHMuQ2xpZW50VmVoaWNsZUVudGl0eS5tX3BQaHlzaWNzRW50aXR5KTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoUlBNLklzVmFsaWQocER5bmFtaWNQaHlzaWNzRW50aXR5KSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IHBQaHlzaWNzRW50aXR5ID0gUlBNLlJlYWQ8SW50NjQ+KHBEeW5hbWljUGh5c2ljc0VudGl0eSArIE9mZnNldHMuRHluYW1pY1BoeXNpY3NFbnRpdHkubV9FbnRpdHlUcmFuc2Zvcm0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF5ZXIuVmVoaWNsZVRyYW5mc29ybSA9IFJQTS5SZWFkPE1hdHJpeD4ocFBoeXNpY3NFbnRpdHkgKyBPZmZzZXRzLlBoeXNpY3NFbnRpdHlUcmFuc2Zvcm0ubV9UcmFuc2Zvcm0pOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF5ZXIuVmVoaWNsZUFBQkIgPSBSUE0uUmVhZDxBeGlzQWxpZ25lZEJveD4ocFZlaGljbGVFbnRpdHkgKyBPZmZzZXRzLkNsaWVudFZlaGljbGVFbnRpdHkubV9jaGlsZHJlbkFBQkIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IF9FbnRpdHlEYXRhID0gUlBNLlJlYWQ8SW50NjQ+KHBWZWhpY2xlRW50aXR5ICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fZGF0YSk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoUlBNLklzVmFsaWQoX0VudGl0eURhdGEpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IF9OYW1lU2lkID0gUlBNLlJlYWQ8SW50NjQ+KF9FbnRpdHlEYXRhICsgT2Zmc2V0cy5WZWhpY2xlRW50aXR5RGF0YS5tX05hbWVTaWQpOwoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmcgc3RyTmFtZSA9IFJQTS5SZWFkTmFtZShfTmFtZVNpZCwgMjApOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzdHJOYW1lLkxlbmd0aCA+IDExKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW50NjQgcEF0dGFjaGVkQ2xpZW50ID0gUlBNLlJlYWQ8SW50NjQ+KG1fQ2xpZW50U29sZGllciArIE9mZnNldHMuQ2xpZW50U29sZGllckVudGl0eS5tX3BQbGF5ZXIpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdHRhY2hlZENvbnRyb2xsYWJsZSBNYXggSGVhbHRoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEludDY0IHAgPSBSUE0uUmVhZDxJbnQ2ND4ocEF0dGFjaGVkQ2xpZW50ICsgT2Zmc2V0cy5DbGllbnRQbGF5ZXIubV9wQXR0YWNoZWRDb250cm9sbGFibGUpOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbnQ2NCBwMiA9IFJQTS5SZWFkPEludDY0PihwICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fcEhlYWx0aENvbXBvbmVudCk7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXllci5WZWhpY2xlSGVhbHRoID0gUlBNLlJlYWQ8ZmxvYXQ+KHAyICsgT2Zmc2V0cy5IZWFsdGhDb21wb25lbnQubV92ZWhpY2xlSGVhbHRoKTsKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEF0dGFjaGVkQ29udHJvbGxhYmxlIEhlYWx0aAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF5ZXIuVmVoaWNsZU1heEhlYWx0aCA9IFJQTS5SZWFkPGZsb2F0PihfRW50aXR5RGF0YSArIE9mZnNldHMuVmVoaWNsZUVudGl0eURhdGEubV9Gcm9udE1heEhlYWx0aCk7CgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBdHRhY2hlZENvbnRyb2xsYWJsZSBOYW1lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsYXllci5WZWhpY2xlTmFtZSA9IHN0ck5hbWUuUmVtb3ZlKDAsIDExKTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxheWVyLklzRHJpdmVyID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICByZXR1cm4gbV9DbGllbnRTb2xkaWVyOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBSUE0uUmVhZDxJbnQ2ND4ocENsaWVudFBsYXllciArIE9mZnNldHMuQ2xpZW50UGxheWVyLm1fcENvbnRyb2xsZWRDb250cm9sbGFibGUpOwogICAgICAgIH0KCiAgICAgICAgLy8gR2V0IFdpbmRvdyBSZWN0CiAgICAgICAgcHJpdmF0ZSB2b2lkIFNldFdpbmRvdyhvYmplY3Qgc2VuZGVyKQogICAgICAgIHsKICAgICAgICAgICAgd2hpbGUgKHRydWUpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIEludFB0ciB0YXJnZXRXbmQgPSBJbnRQdHIuWmVybzsKICAgICAgICAgICAgICAgIHRhcmdldFduZCA9IE1hbmFnZWQuRmluZFdpbmRvdyhudWxsLCAiQmF0dGxlZmllbGQgNCIpOwoKICAgICAgICAgICAgICAgIGlmICh0YXJnZXRXbmQgIT0gSW50UHRyLlplcm8pCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgUkVDVCB0YXJnZXRTaXplID0gbmV3IFJFQ1QoKTsKICAgICAgICAgICAgICAgICAgICBNYW5hZ2VkLkdldFdpbmRvd1JlY3QodGFyZ2V0V25kLCBvdXQgdGFyZ2V0U2l6ZSk7CgogICAgICAgICAgICAgICAgICAgIC8vIEdhbWUgaXMgTWluaW1pemVkCiAgICAgICAgICAgICAgICAgICAgaWYgKHRhcmdldFNpemUuTGVmdCA8IDAgJiYgdGFyZ2V0U2l6ZS5Ub3AgPCAwICYmIHRhcmdldFNpemUuUmlnaHQgPCAwICYmIHRhcmdldFNpemUuQm90dG9tIDwgMCkKICAgICAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgICAgIElzTWluaW1pemVkID0gdHJ1ZTsKICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgICAgICAvLyBSZXNldAogICAgICAgICAgICAgICAgICAgIElzTWluaW1pemVkID0gZmFsc2U7CgogICAgICAgICAgICAgICAgICAgIFJFQ1QgYm9yZGVyU2l6ZSA9IG5ldyBSRUNUKCk7CiAgICAgICAgICAgICAgICAgICAgTWFuYWdlZC5HZXRDbGllbnRSZWN0KHRhcmdldFduZCwgb3V0IGJvcmRlclNpemUpOwoKICAgICAgICAgICAgICAgICAgICBpbnQgZHdTdHlsZSA9IE1hbmFnZWQuR2V0V2luZG93TG9uZyh0YXJnZXRXbmQsIE1hbmFnZWQuR1dMX1NUWUxFKTsKCiAgICAgICAgICAgICAgICAgICAgaW50IHdpbmRvd2hlaWdodDsKICAgICAgICAgICAgICAgICAgICBpbnQgd2luZG93d2lkdGg7CiAgICAgICAgICAgICAgICAgICAgaW50IGJvcmRlcmhlaWdodDsKICAgICAgICAgICAgICAgICAgICBpbnQgYm9yZGVyd2lkdGg7CgogICAgICAgICAgICAgICAgICAgIGlmIChyZWN0LldpZHRoICE9ICh0YXJnZXRTaXplLkJvdHRvbSAtIHRhcmdldFNpemUuVG9wKQogICAgICAgICAgICAgICAgICAgICAgICAmJiByZWN0LldpZHRoICE9IChib3JkZXJTaXplLlJpZ2h0IC0gYm9yZGVyU2l6ZS5MZWZ0KSkKICAgICAgICAgICAgICAgICAgICAgICAgSXNSZXNpemUgPSB0cnVlOwoKICAgICAgICAgICAgICAgICAgICByZWN0LldpZHRoID0gdGFyZ2V0U2l6ZS5SaWdodCAtIHRhcmdldFNpemUuTGVmdDsKICAgICAgICAgICAgICAgICAgICByZWN0LkhlaWdodCA9IHRhcmdldFNpemUuQm90dG9tIC0gdGFyZ2V0U2l6ZS5Ub3A7CgogICAgICAgICAgICAgICAgICAgIGlmICgoZHdTdHlsZSAmIE1hbmFnZWQuV1NfQk9SREVSKSAhPSAwKQogICAgICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93aGVpZ2h0ID0gdGFyZ2V0U2l6ZS5Cb3R0b20gLSB0YXJnZXRTaXplLlRvcDsKICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93d2lkdGggPSB0YXJnZXRTaXplLlJpZ2h0IC0gdGFyZ2V0U2l6ZS5MZWZ0OwoKICAgICAgICAgICAgICAgICAgICAgICAgcmVjdC5IZWlnaHQgPSBib3JkZXJTaXplLkJvdHRvbSAtIGJvcmRlclNpemUuVG9wOwogICAgICAgICAgICAgICAgICAgICAgICByZWN0LldpZHRoID0gYm9yZGVyU2l6ZS5SaWdodCAtIGJvcmRlclNpemUuTGVmdDsKCiAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcmhlaWdodCA9ICh3aW5kb3doZWlnaHQgLSBib3JkZXJTaXplLkJvdHRvbSk7CiAgICAgICAgICAgICAgICAgICAgICAgIGJvcmRlcndpZHRoID0gKHdpbmRvd3dpZHRoIC0gYm9yZGVyU2l6ZS5SaWdodCkgLyAyOyAvL29ubHkgd2FudCBvbmUgc2lkZQogICAgICAgICAgICAgICAgICAgICAgICBib3JkZXJoZWlnaHQgLT0gYm9yZGVyd2lkdGg7IC8vcmVtb3ZlIGJvdHRvbQoKICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0U2l6ZS5MZWZ0ICs9IGJvcmRlcndpZHRoOwogICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRTaXplLlRvcCArPSBib3JkZXJoZWlnaHQ7CgogICAgICAgICAgICAgICAgICAgICAgICByZWN0LkxlZnQgPSB0YXJnZXRTaXplLkxlZnQ7CiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3QuVG9wID0gdGFyZ2V0U2l6ZS5Ub3A7CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgICAgIE1hbmFnZWQuTW92ZVdpbmRvdyhoYW5kbGUsIHRhcmdldFNpemUuTGVmdCwgdGFyZ2V0U2l6ZS5Ub3AsIHJlY3QuV2lkdGgsIHJlY3QuSGVpZ2h0LCB0cnVlKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIFRocmVhZC5TbGVlcCgzMDApOwogICAgICAgICAgICB9CiAgICAgICAgfSAKCiAgICAgICAgLy8gM0QgSW4gMkQKICAgICAgICBwcml2YXRlIGJvb2wgV29ybGRUb1NjcmVlbihWZWN0b3IzIF9FbmVteSwgaW50IF9Qb3NlLCBvdXQgVmVjdG9yMyBfU2NyZWVuKQogICAgICAgIHsKICAgICAgICAgICAgX1NjcmVlbiA9IG5ldyBWZWN0b3IzKDAsIDAsIDApOwogICAgICAgICAgICBmbG9hdCBIZWFkSGVpZ2h0ID0gX0VuZW15Llk7CgogICAgICAgICAgICAjcmVnaW9uIEhlYWRIZWlnaHQKICAgICAgICAgICAgaWYgKF9Qb3NlID09IDApCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIEhlYWRIZWlnaHQgKz0gMS43ZjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoX1Bvc2UgPT0gMSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgSGVhZEhlaWdodCArPSAxLjE1ZjsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiAoX1Bvc2UgPT0gMikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgSGVhZEhlaWdodCArPSAwLjRmOwogICAgICAgICAgICB9CiAgICAgICAgICAgICNlbmRyZWdpb24KCiAgICAgICAgICAgIGZsb2F0IFNjcmVlblcgPSAodmlld1Byb2ouTTE0ICogX0VuZW15LlgpICsgKHZpZXdQcm9qLk0yNCAqIEhlYWRIZWlnaHQpICsgKHZpZXdQcm9qLk0zNCAqIF9FbmVteS5aICsgdmlld1Byb2ouTTQ0KTsKCiAgICAgICAgICAgIGlmIChTY3JlZW5XIDwgMC4wMDAxZikKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKCiAgICAgICAgICAgIGZsb2F0IFNjcmVlblggPSAodmlld1Byb2ouTTExICogX0VuZW15LlgpICsgKHZpZXdQcm9qLk0yMSAqIEhlYWRIZWlnaHQpICsgKHZpZXdQcm9qLk0zMSAqIF9FbmVteS5aICsgdmlld1Byb2ouTTQxKTsKICAgICAgICAgICAgZmxvYXQgU2NyZWVuWSA9ICh2aWV3UHJvai5NMTIgKiBfRW5lbXkuWCkgKyAodmlld1Byb2ouTTIyICogSGVhZEhlaWdodCkgKyAodmlld1Byb2ouTTMyICogX0VuZW15LlogKyB2aWV3UHJvai5NNDIpOwoKICAgICAgICAgICAgX1NjcmVlbi5YID0gKHJlY3QuV2lkdGggLyAyKSArIChyZWN0LldpZHRoIC8gMikgKiBTY3JlZW5YIC8gU2NyZWVuVzsKICAgICAgICAgICAgX1NjcmVlbi5ZID0gKHJlY3QuSGVpZ2h0IC8gMikgLSAocmVjdC5IZWlnaHQgLyAyKSAqIFNjcmVlblkgLyBTY3JlZW5XOwogICAgICAgICAgICBfU2NyZWVuLlogPSBTY3JlZW5XOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CgogICAgICAgIC8vIDNEIEluIDJECiAgICAgICAgcHJpdmF0ZSBib29sIFdvcmxkVG9TY3JlZW4oVmVjdG9yMyBfRW5lbXksIG91dCBWZWN0b3IzIF9TY3JlZW4pCiAgICAgICAgewogICAgICAgICAgICBfU2NyZWVuID0gbmV3IFZlY3RvcjMoMCwgMCwgMCk7CiAgICAgICAgICAgIGZsb2F0IFNjcmVlblcgPSAodmlld1Byb2ouTTE0ICogX0VuZW15LlgpICsgKHZpZXdQcm9qLk0yNCAqIF9FbmVteS5ZKSArICh2aWV3UHJvai5NMzQgKiBfRW5lbXkuWiArIHZpZXdQcm9qLk00NCk7CgogICAgICAgICAgICBpZiAoU2NyZWVuVyA8IDAuMDAwMWYpCiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7CgogICAgICAgICAgICBmbG9hdCBTY3JlZW5YID0gKHZpZXdQcm9qLk0xMSAqIF9FbmVteS5YKSArICh2aWV3UHJvai5NMjEgKiBfRW5lbXkuWSkgKyAodmlld1Byb2ouTTMxICogX0VuZW15LlogKyB2aWV3UHJvai5NNDEpOwogICAgICAgICAgICBmbG9hdCBTY3JlZW5ZID0gKHZpZXdQcm9qLk0xMiAqIF9FbmVteS5YKSArICh2aWV3UHJvai5NMjIgKiBfRW5lbXkuWSkgKyAodmlld1Byb2ouTTMyICogX0VuZW15LlogKyB2aWV3UHJvai5NNDIpOwoKICAgICAgICAgICAgX1NjcmVlbi5YID0gKHJlY3QuV2lkdGggLyAyKSArIChyZWN0LldpZHRoIC8gMikgKiBTY3JlZW5YIC8gU2NyZWVuVzsKICAgICAgICAgICAgX1NjcmVlbi5ZID0gKHJlY3QuSGVpZ2h0IC8gMikgLSAocmVjdC5IZWlnaHQgLyAyKSAqIFNjcmVlblkgLyBTY3JlZW5XOwogICAgICAgICAgICBfU2NyZWVuLlogPSBTY3JlZW5XOwogICAgICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgICB9CgogICAgICAgIC8vIEdldCBSb2xsCiAgICAgICAgcHJpdmF0ZSBib29sIEdldEJvbnlCeUlkKEludDY0IHBFbmVteVNvbGRpZXIsIGludCBJZCwgb3V0IFZlY3RvcjMgX1dvcmxkKQogICAgICAgIHsKICAgICAgICAgICAgX1dvcmxkID0gbmV3IFZlY3RvcjMoKTsKCiAgICAgICAgICAgIEludDY0IHBSYWdkb2xsQ29tcCA9IFJQTS5SZWFkPEludDY0PihwRW5lbXlTb2xkaWVyICsgT2Zmc2V0cy5DbGllbnRTb2xkaWVyRW50aXR5Lm1fcmFnZG9sbENvbXBvbmVudCk7CiAgICAgICAgICAgIGlmICghUlBNLklzVmFsaWQocFJhZ2RvbGxDb21wKSkKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKCiAgICAgICAgICAgIGJ5dGUgbV9WYWxpZFRyYW5zZm9ybXMgPSBSUE0uUmVhZDxCeXRlPihwUmFnZG9sbENvbXAgKyAoT2Zmc2V0cy5DbGllbnRSYWdEb2xsQ29tcG9uZW50Lm1fcmFnZG9sbFRyYW5zZm9ybXMgKyBPZmZzZXRzLlVwZGF0ZVBvc2VSZXN1bHREYXRhLm1fVmFsaWRUcmFuc2Zvcm1zKSk7CiAgICAgICAgICAgIGlmIChtX1ZhbGlkVHJhbnNmb3JtcyAhPSAxKQogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOwoKICAgICAgICAgICAgSW50NjQgcFF1YXRUcmFuc2Zvcm0gPSBSUE0uUmVhZDxJbnQ2ND4ocFJhZ2RvbGxDb21wICsgKE9mZnNldHMuQ2xpZW50UmFnRG9sbENvbXBvbmVudC5tX3JhZ2RvbGxUcmFuc2Zvcm1zICsgT2Zmc2V0cy5VcGRhdGVQb3NlUmVzdWx0RGF0YS5tX0FjdGl2ZVdvcmxkVHJhbnNmb3JtcykpOwogICAgICAgICAgICBpZiAoIVJQTS5Jc1ZhbGlkKHBRdWF0VHJhbnNmb3JtKSkKICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTsKCiAgICAgICAgICAgIF9Xb3JsZCA9IFJQTS5SZWFkPFZlY3RvcjM+KHBRdWF0VHJhbnNmb3JtICsgSWQgKiAweDIwKTsKICAgICAgICAgICAgcmV0dXJuIHRydWU7CiAgICAgICAgfSAKCiAgICAgICAgLy8gR2V0IEZQUwogICAgICAgIHB1YmxpYyBpbnQgQ2FsY3VsYXRlRnJhbWVSYXRlKCkKICAgICAgICB7CiAgICAgICAgICAgIGludCB0aWNrQ291bnQgPSBFbnZpcm9ubWVudC5UaWNrQ291bnQ7CiAgICAgICAgICAgIGlmICh0aWNrQ291bnQgLSBsYXN0VGljayA+PSAxMDAwKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBsYXN0RnJhbWVSYXRlID0gZnJhbWVSYXRlOwogICAgICAgICAgICAgICAgZnJhbWVSYXRlID0gMDsKICAgICAgICAgICAgICAgIGxhc3RUaWNrID0gdGlja0NvdW50OwogICAgICAgICAgICB9CiAgICAgICAgICAgIGZyYW1lUmF0ZSsrOwogICAgICAgICAgICByZXR1cm4gbGFzdEZyYW1lUmF0ZTsKICAgICAgICB9CgogICAgICAgIC8vIENsb3NlIHdpbmRvdyBldmVudAogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3V2luZG93X0Zvcm1DbG9zaW5nKG9iamVjdCBzZW5kZXIsIEZvcm1DbG9zaW5nRXZlbnRBcmdzIGUpCiAgICAgICAgewogICAgICAgICAgICB1cGRhdGVTdHJlYW0uQWJvcnQoKTsKICAgICAgICAgICAgd2luZG93U3RyZWFtLkFib3J0KCk7CiAgICAgICAgICAgIFJQTS5DbG9zZVByb2Nlc3MoKTsKCiAgICAgICAgICAgIC8vIENsb3NlIG1haW4gcHJvY2VzcwogICAgICAgICAgICBFbnZpcm9ubWVudC5FeGl0KDApOwogICAgICAgIH0KCiAgICAgICAgLy8gTXVsdGlwbHkgVmVjdG9yJ3MKICAgICAgICBwdWJsaWMgVmVjdG9yMyBNdWx0aXBseShWZWN0b3IzIHZlY3RvciwgTWF0cml4IG1hdCkKICAgICAgICB7CiAgICAgICAgICAgIHJldHVybiBuZXcgVmVjdG9yMyhtYXQuTTExICogdmVjdG9yLlggKyBtYXQuTTIxICogdmVjdG9yLlkgKyBtYXQuTTMxICogdmVjdG9yLlosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0Lk0xMiAqIHZlY3Rvci5YICsgbWF0Lk0yMiAqIHZlY3Rvci5ZICsgbWF0Lk0zMiAqIHZlY3Rvci5aLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdC5NMTMgKiB2ZWN0b3IuWCArIG1hdC5NMjMgKiB2ZWN0b3IuWSArIG1hdC5NMzMgKiB2ZWN0b3IuWik7CiAgICAgICAgfQoKICAgICAgICAvLyBEcmF3IEZ1bmN0aW9ucwogICAgICAgICNyZWdpb24gRHJhdyBGdW5jdGlvbnMKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1JlY3QoaW50IFgsIGludCBZLCBpbnQgVywgaW50IEgsIENvbG9yIGNvbG9yKQogICAgICAgIHsKICAgICAgICAgICAgc29saWRDb2xvckJydXNoLkNvbG9yID0gY29sb3I7CiAgICAgICAgICAgIGRldmljZS5EcmF3UmVjdGFuZ2xlKG5ldyBSZWN0YW5nbGUoWCwgWSwgVywgSCksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1JlY3QoaW50IFgsIGludCBZLCBpbnQgVywgaW50IEgsIENvbG9yIGNvbG9yLCBmbG9hdCBzdHJva2UpCiAgICAgICAgewogICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBjb2xvcjsKICAgICAgICAgICAgZGV2aWNlLkRyYXdSZWN0YW5nbGUobmV3IFJlY3RhbmdsZShYLCBZLCBXLCBIKSwgc29saWRDb2xvckJydXNoLCBzdHJva2UpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdGaWxsUmVjdChpbnQgWCwgaW50IFksIGludCBXLCBpbnQgSCwgQ29sb3IgY29sb3IpCiAgICAgICAgewogICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBjb2xvcjsKICAgICAgICAgICAgZGV2aWNlLkZpbGxSZWN0YW5nbGUobmV3IFJlY3RhbmdsZUYoWCwgWSwgVywgSCksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1RleHQoaW50IFgsIGludCBZLCBzdHJpbmcgdGV4dCwgQ29sb3IgY29sb3IpCiAgICAgICAgewogICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBjb2xvcjsKICAgICAgICAgICAgZGV2aWNlLkRyYXdUZXh0KHRleHQsIGZvbnQsIG5ldyBSZWN0YW5nbGVGKFgsIFksIGZvbnQuRm9udFNpemUgKiB0ZXh0Lkxlbmd0aCwgZm9udC5Gb250U2l6ZSksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1RleHQoaW50IFgsIGludCBZLCBzdHJpbmcgdGV4dCwgQ29sb3IgY29sb3IsIGJvb2wgb3V0bGluZSkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChvdXRsaW5lKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBDb2xvci5CbGFjazsKICAgICAgICAgICAgICAgIGRldmljZS5EcmF3VGV4dCh0ZXh0LCBmb250LCBuZXcgUmVjdGFuZ2xlRihYICsgMSwgWSArIDEsIGZvbnQuRm9udFNpemUgKiB0ZXh0Lkxlbmd0aCwgZm9udC5Gb250U2l6ZSksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHNvbGlkQ29sb3JCcnVzaC5Db2xvciA9IGNvbG9yOwogICAgICAgICAgICBkZXZpY2UuRHJhd1RleHQodGV4dCwgZm9udCwgbmV3IFJlY3RhbmdsZUYoWCwgWSwgZm9udC5Gb250U2l6ZSAqIHRleHQuTGVuZ3RoLCBmb250LkZvbnRTaXplKSwgc29saWRDb2xvckJydXNoKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3VGV4dChpbnQgWCwgaW50IFksIHN0cmluZyB0ZXh0LCBDb2xvciBjb2xvciwgYm9vbCBvdXRsaW5lLCBUZXh0Rm9ybWF0IGZvcm1hdCkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChvdXRsaW5lKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBDb2xvci5CbGFjazsKICAgICAgICAgICAgICAgIGRldmljZS5EcmF3VGV4dCh0ZXh0LCBmb3JtYXQsIG5ldyBSZWN0YW5nbGVGKFggKyAxLCBZICsgMSwgZm9ybWF0LkZvbnRTaXplICogdGV4dC5MZW5ndGgsIGZvcm1hdC5Gb250U2l6ZSksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIHNvbGlkQ29sb3JCcnVzaC5Db2xvciA9IGNvbG9yOwogICAgICAgICAgICBkZXZpY2UuRHJhd1RleHQodGV4dCwgZm9ybWF0LCBuZXcgUmVjdGFuZ2xlRihYLCBZLCBmb3JtYXQuRm9udFNpemUgKiB0ZXh0Lkxlbmd0aCwgZm9ybWF0LkZvbnRTaXplKSwgc29saWRDb2xvckJydXNoKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3VGV4dENlbnRlcihpbnQgWCwgaW50IFksIGludCBXLCBpbnQgSCwgc3RyaW5nIHRleHQsIENvbG9yIGNvbG9yKQogICAgICAgIHsKICAgICAgICAgICAgc29saWRDb2xvckJydXNoLkNvbG9yID0gY29sb3I7CiAgICAgICAgICAgIFRleHRMYXlvdXQgbGF5b3V0ID0gbmV3IFRleHRMYXlvdXQoZm9udEZhY3RvcnksIHRleHQsIGZvbnRTbWFsbCwgVywgSCk7CiAgICAgICAgICAgIGxheW91dC5UZXh0QWxpZ25tZW50ID0gVGV4dEFsaWdubWVudC5DZW50ZXI7CiAgICAgICAgICAgIGRldmljZS5EcmF3VGV4dExheW91dChuZXcgVmVjdG9yMihYLCBZKSwgbGF5b3V0LCBzb2xpZENvbG9yQnJ1c2gpOwogICAgICAgICAgICBsYXlvdXQuRGlzcG9zZSgpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdUZXh0Q2VudGVyKGludCBYLCBpbnQgWSwgaW50IFcsIGludCBILCBzdHJpbmcgdGV4dCwgQ29sb3IgY29sb3IsIGJvb2wgb3V0bGluZSkKICAgICAgICB7CiAgICAgICAgICAgIFRleHRMYXlvdXQgbGF5b3V0ID0gbmV3IFRleHRMYXlvdXQoZm9udEZhY3RvcnksIHRleHQsIGZvbnRTbWFsbCwgVywgSCk7CiAgICAgICAgICAgIGxheW91dC5UZXh0QWxpZ25tZW50ID0gVGV4dEFsaWdubWVudC5DZW50ZXI7CgogICAgICAgICAgICBpZiAob3V0bGluZSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgc29saWRDb2xvckJydXNoLkNvbG9yID0gQ29sb3IuQmxhY2s7CiAgICAgICAgICAgICAgICBkZXZpY2UuRHJhd1RleHRMYXlvdXQobmV3IFZlY3RvcjIoWCArIDEsIFkgKyAxKSwgbGF5b3V0LCBzb2xpZENvbG9yQnJ1c2gpOwogICAgICAgICAgICB9CgogICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBjb2xvcjsKICAgICAgICAgICAgZGV2aWNlLkRyYXdUZXh0TGF5b3V0KG5ldyBWZWN0b3IyKFgsIFkpLCBsYXlvdXQsIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgICAgIGxheW91dC5EaXNwb3NlKCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd0xpbmUoaW50IFgsIGludCBZLCBpbnQgWFgsIGludCBZWSwgQ29sb3IgY29sb3IpCiAgICAgICAgewogICAgICAgICAgICBzb2xpZENvbG9yQnJ1c2guQ29sb3IgPSBjb2xvcjsKICAgICAgICAgICAgZGV2aWNlLkRyYXdMaW5lKG5ldyBWZWN0b3IyKFgsIFkpLCBuZXcgVmVjdG9yMihYWCwgWVkpLCBzb2xpZENvbG9yQnJ1c2gpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdMaW5lKFZlY3RvcjMgdzJzLCBWZWN0b3IzIF93MnMsIENvbG9yIGNvbG9yKQogICAgICAgIHsKICAgICAgICAgICAgc29saWRDb2xvckJydXNoLkNvbG9yID0gY29sb3I7CiAgICAgICAgICAgIGRldmljZS5EcmF3TGluZShuZXcgVmVjdG9yMih3MnMuWCwgdzJzLlkpLCBuZXcgVmVjdG9yMihfdzJzLlgsIF93MnMuWSksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd0NpcmNsZShpbnQgWCwgaW50IFksIGludCBXLCBDb2xvciBjb2xvcikKICAgICAgICB7CiAgICAgICAgICAgIHNvbGlkQ29sb3JCcnVzaC5Db2xvciA9IGNvbG9yOwogICAgICAgICAgICBkZXZpY2UuRHJhd0VsbGlwc2UobmV3IEVsbGlwc2UobmV3IFZlY3RvcjIoWCwgWSksIFcsIFcpLCBzb2xpZENvbG9yQnJ1c2gpOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdGaWxsQ2lyY2xlKGludCBYLCBpbnQgWSwgaW50IFcsIENvbG9yIGNvbG9yKQogICAgICAgIHsKICAgICAgICAgICAgc29saWRDb2xvckJydXNoLkNvbG9yID0gY29sb3I7CiAgICAgICAgICAgIGRldmljZS5GaWxsRWxsaXBzZShuZXcgRWxsaXBzZShuZXcgVmVjdG9yMihYLCBZKSwgVywgVyksIHNvbGlkQ29sb3JCcnVzaCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd0ltYWdlKGludCBYLCBpbnQgWSwgaW50IFcsIGludCBILCBCaXRtYXAgYml0bWFwKQogICAgICAgIHsKICAgICAgICAgICAgZGV2aWNlLkRyYXdCaXRtYXAoYml0bWFwLCBuZXcgUmVjdGFuZ2xlRihYLCBZLCBXLCBIKSwgMS4wZiwgQml0bWFwSW50ZXJwb2xhdGlvbk1vZGUuTGluZWFyKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3SW1hZ2UoaW50IFgsIGludCBZLCBpbnQgVywgaW50IEgsIEJpdG1hcCBiaXRtYXAsIGZsb2F0IGFuZ2xlKQogICAgICAgIHsKICAgICAgICAgICAgZGV2aWNlLlRyYW5zZm9ybSA9IE1hdHJpeDN4Mi5Sb3RhdGlvbihhbmdsZSwgbmV3IFZlY3RvcjIoWCArIChIIC8gMiksIFkgKyAoSCAvIDIpKSk7CiAgICAgICAgICAgIGRldmljZS5EcmF3Qml0bWFwKGJpdG1hcCwgbmV3IFJlY3RhbmdsZUYoWCwgWSwgVywgSCksIDEuMGYsIEJpdG1hcEludGVycG9sYXRpb25Nb2RlLkxpbmVhcik7CiAgICAgICAgICAgIGRldmljZS5UcmFuc2Zvcm0gPSBNYXRyaXgzeDIuUm90YXRpb24oMCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1Nwcml0ZShSZWN0YW5nbGVGIGRlc3RpbmF0aW9uUmVjdGFuZ2xlLCBCaXRtYXAgYml0bWFwLCBSZWN0YW5nbGVGIHNvdXJjZVJlY3RhbmdsZSkKICAgICAgICB7CiAgICAgICAgICAgIGRldmljZS5EcmF3Qml0bWFwKGJpdG1hcCwgZGVzdGluYXRpb25SZWN0YW5nbGUsIDEuMGYsIEJpdG1hcEludGVycG9sYXRpb25Nb2RlLkxpbmVhciwgc291cmNlUmVjdGFuZ2xlKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3U3ByaXRlKFJlY3RhbmdsZUYgZGVzdGluYXRpb25SZWN0YW5nbGUsIEJpdG1hcCBiaXRtYXAsIFJlY3RhbmdsZUYgc291cmNlUmVjdGFuZ2xlLCBmbG9hdCBhbmdsZSkKICAgICAgICB7CiAgICAgICAgICAgIFZlY3RvcjIgY2VudGVyID0gbmV3IFZlY3RvcjIoKTsKICAgICAgICAgICAgY2VudGVyLlggPSBkZXN0aW5hdGlvblJlY3RhbmdsZS5YICsgZGVzdGluYXRpb25SZWN0YW5nbGUuV2lkdGggLyAyOwogICAgICAgICAgICBjZW50ZXIuWSA9IGRlc3RpbmF0aW9uUmVjdGFuZ2xlLlkgKyBkZXN0aW5hdGlvblJlY3RhbmdsZS5IZWlnaHQgLyAyOwoKICAgICAgICAgICAgZGV2aWNlLlRyYW5zZm9ybSA9IE1hdHJpeDN4Mi5Sb3RhdGlvbihhbmdsZSwgY2VudGVyKTsKICAgICAgICAgICAgZGV2aWNlLkRyYXdCaXRtYXAoYml0bWFwLCBkZXN0aW5hdGlvblJlY3RhbmdsZSwgMS4wZiwgQml0bWFwSW50ZXJwb2xhdGlvbk1vZGUuTGluZWFyLCBzb3VyY2VSZWN0YW5nbGUpOwogICAgICAgICAgICBkZXZpY2UuVHJhbnNmb3JtID0gTWF0cml4M3gyLlJvdGF0aW9uKDApOwogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdCb25lKFBsYXllciBwbGF5ZXIpCiAgICAgICAgewogICAgICAgICAgICBWZWN0b3IzIEJPTkVfSEVBRCwKICAgICAgICAgICAgQk9ORV9ORUNLLAogICAgICAgICAgICBCT05FX1NQSU5FMiwKICAgICAgICAgICAgQk9ORV9TUElORTEsCiAgICAgICAgICAgIEJPTkVfU1BJTkUsCiAgICAgICAgICAgIEJPTkVfTEVGVFNIT1VMREVSLAogICAgICAgICAgICBCT05FX1JJR0hUU0hPVUxERVIsCiAgICAgICAgICAgIEJPTkVfTEVGVEVMQk9XUk9MTCwKICAgICAgICAgICAgQk9ORV9SSUdIVEVMQk9XUk9MTCwKICAgICAgICAgICAgQk9ORV9MRUZUSEFORCwKICAgICAgICAgICAgQk9ORV9SSUdIVEhBTkQsCiAgICAgICAgICAgIEJPTkVfTEVGVEtORUVST0xMLAogICAgICAgICAgICBCT05FX1JJR0hUS05FRVJPTEwsCiAgICAgICAgICAgIEJPTkVfTEVGVEZPT1QsCiAgICAgICAgICAgIEJPTkVfUklHSFRGT09UOwoKICAgICAgICAgICAgaWYoV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX0hFQUQsIG91dCBCT05FX0hFQUQpICYmCiAgICAgICAgICAgIFdvcmxkVG9TY3JlZW4ocGxheWVyLkJvbmUuQk9ORV9ORUNLLCBvdXQgQk9ORV9ORUNLKSAmJgogICAgICAgICAgICBXb3JsZFRvU2NyZWVuKHBsYXllci5Cb25lLkJPTkVfU1BJTkUyLCBvdXQgQk9ORV9TUElORTIpICYmCiAgICAgICAgICAgIFdvcmxkVG9TY3JlZW4ocGxheWVyLkJvbmUuQk9ORV9TUElORTEsIG91dCBCT05FX1NQSU5FMSkgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX1NQSU5FLCBvdXQgQk9ORV9TUElORSkgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX0xFRlRTSE9VTERFUiwgb3V0IEJPTkVfTEVGVFNIT1VMREVSKSAmJgogICAgICAgICAgICBXb3JsZFRvU2NyZWVuKHBsYXllci5Cb25lLkJPTkVfUklHSFRTSE9VTERFUiwgb3V0IEJPTkVfUklHSFRTSE9VTERFUikgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX0xFRlRFTEJPV1JPTEwsIG91dCBCT05FX0xFRlRFTEJPV1JPTEwpICYmCiAgICAgICAgICAgIFdvcmxkVG9TY3JlZW4ocGxheWVyLkJvbmUuQk9ORV9SSUdIVEVMQk9XUk9MTCwgb3V0IEJPTkVfUklHSFRFTEJPV1JPTEwpICYmCiAgICAgICAgICAgIFdvcmxkVG9TY3JlZW4ocGxheWVyLkJvbmUuQk9ORV9MRUZUSEFORCwgb3V0IEJPTkVfTEVGVEhBTkQpICYmCiAgICAgICAgICAgIFdvcmxkVG9TY3JlZW4ocGxheWVyLkJvbmUuQk9ORV9SSUdIVEhBTkQsIG91dCBCT05FX1JJR0hUSEFORCkgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX0xFRlRLTkVFUk9MTCwgb3V0IEJPTkVfTEVGVEtORUVST0xMKSAmJgogICAgICAgICAgICBXb3JsZFRvU2NyZWVuKHBsYXllci5Cb25lLkJPTkVfUklHSFRLTkVFUk9MTCwgb3V0IEJPTkVfUklHSFRLTkVFUk9MTCkgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX0xFRlRGT09ULCBvdXQgQk9ORV9MRUZURk9PVCkgJiYKICAgICAgICAgICAgV29ybGRUb1NjcmVlbihwbGF5ZXIuQm9uZS5CT05FX1JJR0hURk9PVCwgb3V0IEJPTkVfUklHSFRGT09UKSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaW50IHN0cm9rZSA9IDM7CiAgICAgICAgICAgICAgICBpbnQgc3Ryb2tlVyA9IHN0cm9rZSAlIDIgPT0gMCA/IHN0cm9rZSAvIDIgOiAoc3Ryb2tlIC0gMSkgLyAyOwoKICAgICAgICAgICAgICAgIC8vIENvbG9yCiAgICAgICAgICAgICAgICBDb2xvciBza2VsZXRvbkNvbG9yID0gcGxheWVyLlRlYW0gPT0gbG9jYWxQbGF5ZXIuVGVhbSA/IGZyaWVuZFNrZWxldG9uQ29sb3IgOiBlbmVteVNrZWxldG9uQ29sb3I7CgogICAgICAgICAgICAgICAgLy8gUkVDVCdzCgkJICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX0hFQUQuWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9IRUFELlkgLSBzdHJva2VXLCBzdHJva2UsIHN0cm9rZSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX05FQ0suWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9ORUNLLlkgLSBzdHJva2VXLCBzdHJva2UsIHN0cm9rZSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX0xFRlRTSE9VTERFUi5YIC0gc3Ryb2tlVywgKGludClCT05FX0xFRlRTSE9VTERFUi5ZIC0gc3Ryb2tlVywgc3Ryb2tlLCBzdHJva2UsIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0ZpbGxSZWN0KChpbnQpQk9ORV9MRUZURUxCT1dST0xMLlggLSBzdHJva2VXLCAoaW50KUJPTkVfTEVGVEVMQk9XUk9MTC5ZIC0gc3Ryb2tlVywgc3Ryb2tlLCBzdHJva2UsIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0ZpbGxSZWN0KChpbnQpQk9ORV9MRUZUSEFORC5YIC0gc3Ryb2tlVywgKGludClCT05FX0xFRlRIQU5ELlkgLSBzdHJva2VXLCBzdHJva2UsIHN0cm9rZSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX1JJR0hUU0hPVUxERVIuWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9SSUdIVFNIT1VMREVSLlkgLSBzdHJva2VXLCBzdHJva2UsIHN0cm9rZSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX1JJR0hURUxCT1dST0xMLlggLSBzdHJva2VXLCAoaW50KUJPTkVfUklHSFRFTEJPV1JPTEwuWSAtIHN0cm9rZVcsIHN0cm9rZSwgc3Ryb2tlLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdGaWxsUmVjdCgoaW50KUJPTkVfUklHSFRIQU5ELlggLSBzdHJva2VXLCAoaW50KUJPTkVfUklHSFRIQU5ELlkgLSBzdHJva2VXLCBzdHJva2UsIHN0cm9rZSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoKGludClCT05FX1NQSU5FMi5YIC0gc3Ryb2tlVywgKGludClCT05FX1NQSU5FMi5ZIC0gc3Ryb2tlVywgc3Ryb2tlLCBzdHJva2UsIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0ZpbGxSZWN0KChpbnQpQk9ORV9TUElORTEuWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9TUElORTEuWSAtIHN0cm9rZVcsIHN0cm9rZSwgc3Ryb2tlLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdGaWxsUmVjdCgoaW50KUJPTkVfU1BJTkUuWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9TUElORS5ZIC0gc3Ryb2tlVywgc3Ryb2tlLCBzdHJva2UsIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0ZpbGxSZWN0KChpbnQpQk9ORV9MRUZUS05FRVJPTEwuWCAtIHN0cm9rZVcsIChpbnQpQk9ORV9MRUZUS05FRVJPTEwuWSAtIHN0cm9rZVcsIHN0cm9rZSwgc3Ryb2tlLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdGaWxsUmVjdCgoaW50KUJPTkVfUklHSFRLTkVFUk9MTC5YIC0gc3Ryb2tlVywgKGludClCT05FX1JJR0hUS05FRVJPTEwuWSAtIHN0cm9rZVcsIDIsIDIsIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0ZpbGxSZWN0KChpbnQpQk9ORV9MRUZURk9PVC5YIC0gc3Ryb2tlVywgKGludClCT05FX0xFRlRGT09ULlkgLSBzdHJva2VXLCAyLCAyLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdGaWxsUmVjdCgoaW50KUJPTkVfUklHSFRGT09ULlggLSBzdHJva2VXLCAoaW50KUJPTkVfUklHSFRGT09ULlkgLSBzdHJva2VXLCAyLCAyLCBza2VsZXRvbkNvbG9yKTsKCiAgICAgICAgICAgICAgICAvLyBIZWFkIC0+IE5lY2sKCQkgICAgICAgIERyYXdMaW5lKChpbnQpQk9ORV9IRUFELlgsIChpbnQpQk9ORV9IRUFELlksIChpbnQpQk9ORV9ORUNLLlgsIChpbnQpQk9ORV9ORUNLLlksIHNrZWxldG9uQ29sb3IpOwoKCQkgICAgICAgIC8vIE5lY2sgLT4gTGVmdAoJCSAgICAgICAgRHJhd0xpbmUoKGludClCT05FX05FQ0suWCwgKGludClCT05FX05FQ0suWSwgKGludClCT05FX0xFRlRTSE9VTERFUi5YLCAoaW50KUJPTkVfTEVGVFNIT1VMREVSLlksIHNrZWxldG9uQ29sb3IpOwoJCSAgICAgICAgRHJhd0xpbmUoKGludClCT05FX0xFRlRTSE9VTERFUi5YLCAoaW50KUJPTkVfTEVGVFNIT1VMREVSLlksKGludCkgQk9ORV9MRUZURUxCT1dST0xMLlgsIChpbnQpQk9ORV9MRUZURUxCT1dST0xMLlksIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0xpbmUoKGludClCT05FX0xFRlRFTEJPV1JPTEwuWCwgKGludClCT05FX0xFRlRFTEJPV1JPTEwuWSwgKGludClCT05FX0xFRlRIQU5ELlgsIChpbnQpQk9ORV9MRUZUSEFORC5ZLCBza2VsZXRvbkNvbG9yKTsKCgkJICAgICAgICAvLyBOZWNrIC0+IFJpZ2h0CiAgICAgICAgICAgICAgICBEcmF3TGluZSgoaW50KUJPTkVfTkVDSy5YLCAoaW50KUJPTkVfTkVDSy5ZLCAoaW50KUJPTkVfUklHSFRTSE9VTERFUi5YLCAoaW50KUJPTkVfUklHSFRTSE9VTERFUi5ZLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdMaW5lKChpbnQpQk9ORV9SSUdIVFNIT1VMREVSLlgsIChpbnQpQk9ORV9SSUdIVFNIT1VMREVSLlksIChpbnQpQk9ORV9SSUdIVEVMQk9XUk9MTC5YLCAoaW50KUJPTkVfUklHSFRFTEJPV1JPTEwuWSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3TGluZSgoaW50KUJPTkVfUklHSFRFTEJPV1JPTEwuWCwgKGludClCT05FX1JJR0hURUxCT1dST0xMLlksIChpbnQpQk9ORV9SSUdIVEhBTkQuWCwgKGludClCT05FX1JJR0hUSEFORC5ZLCBza2VsZXRvbkNvbG9yKTsKCgkJICAgICAgICAvLyBOZWNrIC0+IENlbnRlcgogICAgICAgICAgICAgICAgRHJhd0xpbmUoKGludClCT05FX05FQ0suWCwgKGludClCT05FX05FQ0suWSwgKGludClCT05FX1NQSU5FMi5YLCAoaW50KUJPTkVfU1BJTkUyLlksIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0xpbmUoKGludClCT05FX1NQSU5FMi5YLCAoaW50KUJPTkVfU1BJTkUyLlksIChpbnQpQk9ORV9TUElORTEuWCwgKGludClCT05FX1NQSU5FMS5ZLCBza2VsZXRvbkNvbG9yKTsKICAgICAgICAgICAgICAgIERyYXdMaW5lKChpbnQpQk9ORV9TUElORTEuWCwgKGludClCT05FX1NQSU5FMS5ZLCAoaW50KUJPTkVfU1BJTkUuWCwgKGludClCT05FX1NQSU5FLlksIHNrZWxldG9uQ29sb3IpOwoKCQkgICAgICAgIC8vIFNwaW5lIC0+IExlZnQKICAgICAgICAgICAgICAgIERyYXdMaW5lKChpbnQpQk9ORV9TUElORS5YLCAoaW50KUJPTkVfU1BJTkUuWSwgKGludClCT05FX0xFRlRLTkVFUk9MTC5YLCAoaW50KUJPTkVfTEVGVEtORUVST0xMLlksIHNrZWxldG9uQ29sb3IpOwogICAgICAgICAgICAgICAgRHJhd0xpbmUoKGludClCT05FX0xFRlRLTkVFUk9MTC5YLCAoaW50KUJPTkVfTEVGVEtORUVST0xMLlksIChpbnQpQk9ORV9MRUZURk9PVC5YLCAoaW50KUJPTkVfTEVGVEZPT1QuWSwgc2tlbGV0b25Db2xvcik7CgoJCSAgICAgICAgLy8gU3BpbmUgLT4gUmlnaHQKICAgICAgICAgICAgICAgIERyYXdMaW5lKChpbnQpQk9ORV9TUElORS5YLCAoaW50KUJPTkVfU1BJTkUuWSwgKGludClCT05FX1JJR0hUS05FRVJPTEwuWCwgKGludClCT05FX1JJR0hUS05FRVJPTEwuWSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgICAgICBEcmF3TGluZSgoaW50KUJPTkVfUklHSFRLTkVFUk9MTC5YLCAoaW50KUJPTkVfUklHSFRLTkVFUk9MTC5ZLCAoaW50KUJPTkVfUklHSFRGT09ULlgsIChpbnQpQk9ORV9SSUdIVEZPT1QuWSwgc2tlbGV0b25Db2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3SGVhbHRoKGludCBYLCBpbnQgWSwgaW50IFcsIGludCBILCBpbnQgSGVhbHRoLCBpbnQgTWF4SGVhbHRoKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKEhlYWx0aCA8PSAwKQogICAgICAgICAgICAgICAgSGVhbHRoID0gMTsKCiAgICAgICAgICAgIGlmIChNYXhIZWFsdGggPCBIZWFsdGgpIAogICAgICAgICAgICAgICAgTWF4SGVhbHRoID0gMTAwOwoKICAgICAgICAgICAgaW50IHByb2dyZXNzID0gKGludCkoKGZsb2F0KUhlYWx0aCAvICgoZmxvYXQpTWF4SGVhbHRoIC8gMTAwKSk7CiAgICAgICAgICAgIGludCB3ID0gKGludCkoKGZsb2F0KVcgLyAxMDAgKiBwcm9ncmVzcyk7CgogICAgICAgICAgICBpZiAodyA8PSAyKQogICAgICAgICAgICAgICAgdyA9IDM7CgogICAgICAgICAgICBDb2xvciBjb2xvciA9IG5ldyBDb2xvcigyNTUsIDAsIDAsIDI1NSk7CiAgICAgICAgICAgIGlmIChwcm9ncmVzcyA+PSAyMCkgY29sb3IgPSBuZXcgQ29sb3IoMjU1LCAxNjUsIDAsIDI1NSk7CiAgICAgICAgICAgIGlmIChwcm9ncmVzcyA+PSA0MCkgY29sb3IgPSBuZXcgQ29sb3IoMjU1LCAyNTUsIDAsIDI1NSk7CiAgICAgICAgICAgIGlmIChwcm9ncmVzcyA+PSA2MCkgY29sb3IgPSBuZXcgQ29sb3IoMTczLCAyNTUsIDQ3LCAyNTUpOwogICAgICAgICAgICBpZiAocHJvZ3Jlc3MgPj0gODApIGNvbG9yID0gbmV3IENvbG9yKDAsIDI1NSwgMCwgMjU1KTsKCiAgICAgICAgICAgIERyYXdGaWxsUmVjdChYLCBZIC0gMSwgVyArIDEsIEggKyAyLCBDb2xvci5CbGFjayk7CiAgICAgICAgICAgIERyYXdGaWxsUmVjdChYICsgMSwgWSwgdyAtIDEsIEgsIGNvbG9yKTsKICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3UHJvZ3Jlc3MoaW50IFgsIGludCBZLCBpbnQgVywgaW50IEgsIGludCBWYWx1ZSwgaW50IE1heFZhbHVlKQogICAgICAgIHsKICAgICAgICAgICAgaW50IHByb2dyZXNzID0gKGludCkoKGZsb2F0KVZhbHVlIC8gKChmbG9hdClNYXhWYWx1ZSAvIDEwMCkpOwogICAgICAgICAgICBpbnQgdyA9IChpbnQpKChmbG9hdClXIC8gMTAwICogcHJvZ3Jlc3MpOwoKICAgICAgICAgICAgQ29sb3IgY29sb3IgPSBuZXcgQ29sb3IoMCwgMjU1LCAwLCAyNTUpOwogICAgICAgICAgICBpZiAocHJvZ3Jlc3MgPj0gMjApIGNvbG9yID0gbmV3IENvbG9yKDE3MywgMjU1LCA0NywgMjU1KTsKICAgICAgICAgICAgaWYgKHByb2dyZXNzID49IDQwKSBjb2xvciA9IG5ldyBDb2xvcigyNTUsIDI1NSwgMCwgMjU1KTsKICAgICAgICAgICAgaWYgKHByb2dyZXNzID49IDYwKSBjb2xvciA9IG5ldyBDb2xvcigyNTUsIDE2NSwgMCwgMjU1KTsKICAgICAgICAgICAgaWYgKHByb2dyZXNzID49IDgwKSBjb2xvciA9IG5ldyBDb2xvcigyNTUsIDAsIDAsIDI1NSk7CgogICAgICAgICAgICBEcmF3RmlsbFJlY3QoWCwgWSAtIDEsIFcgKyAxLCBIICsgMiwgQ29sb3IuQmxhY2spOwogICAgICAgICAgICBpZiAodyA+PSAyKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBEcmF3RmlsbFJlY3QoWCArIDEsIFksIHcgLSAxLCBILCBjb2xvcik7CiAgICAgICAgICAgIH0KICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3QUFCQihBeGlzQWxpZ25lZEJveCBhYWJiLCBNYXRyaXggdHJhbmZvcm0sIENvbG9yIGNvbG9yKQogICAgICAgIHsKICAgICAgICAgICAgVmVjdG9yMyBtX1Bvc2l0aW9uID0gbmV3IFZlY3RvcjModHJhbmZvcm0uTTQxLCB0cmFuZm9ybS5NNDIsIHRyYW5mb3JtLk00Myk7CiAgICAgICAgICAgIFZlY3RvcjMgZmxkID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NaW4uWCwgYWFiYi5NaW4uWSwgYWFiYi5NaW4uWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgYnJ0ID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NYXguWCwgYWFiYi5NYXguWSwgYWFiYi5NYXguWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgYmxkID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NaW4uWCwgYWFiYi5NaW4uWSwgYWFiYi5NYXguWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgZnJ0ID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NYXguWCwgYWFiYi5NYXguWSwgYWFiYi5NaW4uWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgZnJkID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NYXguWCwgYWFiYi5NaW4uWSwgYWFiYi5NaW4uWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgYnJiID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NYXguWCwgYWFiYi5NaW4uWSwgYWFiYi5NYXguWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgYmx0ID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NaW4uWCwgYWFiYi5NYXguWSwgYWFiYi5NYXguWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CiAgICAgICAgICAgIFZlY3RvcjMgZmx0ID0gTXVsdGlwbHkobmV3IFZlY3RvcjMoYWFiYi5NaW4uWCwgYWFiYi5NYXguWSwgYWFiYi5NaW4uWiksIHRyYW5mb3JtKSArIG1fUG9zaXRpb247CgogICAgICAgICAgICAjcmVnaW9uIFdvcmxkVG9TY3JlZW4KICAgICAgICAgICAgaWYgKCFXb3JsZFRvU2NyZWVuKGZsZCwgb3V0IGZsZCkgfHwgIVdvcmxkVG9TY3JlZW4oYnJ0LCBvdXQgYnJ0KQogICAgICAgICAgICAgICAgfHwgIVdvcmxkVG9TY3JlZW4oYmxkLCBvdXQgYmxkKSB8fCAhV29ybGRUb1NjcmVlbihmcnQsIG91dCBmcnQpCiAgICAgICAgICAgICAgICB8fCAhV29ybGRUb1NjcmVlbihmcmQsIG91dCBmcmQpIHx8ICFXb3JsZFRvU2NyZWVuKGJyYiwgb3V0IGJyYikKICAgICAgICAgICAgICAgIHx8ICFXb3JsZFRvU2NyZWVuKGJsdCwgb3V0IGJsdCkgfHwgIVdvcmxkVG9TY3JlZW4oZmx0LCBvdXQgZmx0KSkKICAgICAgICAgICAgICAgIHJldHVybjsKICAgICAgICAgICAgI2VuZHJlZ2lvbgoKICAgICAgICAgICAgI3JlZ2lvbiBEcmF3TGluZXMKICAgICAgICAgICAgRHJhd0xpbmUoZmxkLCBmbHQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZmx0LCBmcnQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJ0LCBmcmQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJkLCBmbGQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoYmxkLCBibHQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoYmx0LCBicnQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoYnJ0LCBicmIsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoYnJiLCBibGQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZmxkLCBibGQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJkLCBicmIsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZmx0LCBibHQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJ0LCBicnQsIGNvbG9yKTsKICAgICAgICAgICAgI2VuZHJlZ2lvbgogICAgICAgIH0KCiAgICAgICAgcHJpdmF0ZSB2b2lkIERyYXdBQUJCKEF4aXNBbGlnbmVkQm94IGFhYmIsIFZlY3RvcjMgbV9Qb3NpdGlvbiwgZmxvYXQgWWF3LCBDb2xvciBjb2xvcikKICAgICAgICB7CiAgICAgICAgICAgIGZsb2F0IGNvc1kgPSAoZmxvYXQpTWF0aC5Db3MoWWF3KTsKICAgICAgICAgICAgZmxvYXQgc2luWSA9IChmbG9hdClNYXRoLlNpbihZYXcpOwoKICAgICAgICAgICAgVmVjdG9yMyBmbGQgPSBuZXcgVmVjdG9yMyhhYWJiLk1pbi5aICogY29zWSAtIGFhYmIuTWluLlggKiBzaW5ZLCBhYWJiLk1pbi5ZLCBhYWJiLk1pbi5YICogY29zWSArIGFhYmIuTWluLlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDAKICAgICAgICAgICAgVmVjdG9yMyBicnQgPSBuZXcgVmVjdG9yMyhhYWJiLk1pbi5aICogY29zWSAtIGFhYmIuTWF4LlggKiBzaW5ZLCBhYWJiLk1pbi5ZLCBhYWJiLk1heC5YICogY29zWSArIGFhYmIuTWluLlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDEKICAgICAgICAgICAgVmVjdG9yMyBibGQgPSBuZXcgVmVjdG9yMyhhYWJiLk1heC5aICogY29zWSAtIGFhYmIuTWF4LlggKiBzaW5ZLCBhYWJiLk1pbi5ZLCBhYWJiLk1heC5YICogY29zWSArIGFhYmIuTWF4LlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDIKICAgICAgICAgICAgVmVjdG9yMyBmcnQgPSBuZXcgVmVjdG9yMyhhYWJiLk1heC5aICogY29zWSAtIGFhYmIuTWluLlggKiBzaW5ZLCBhYWJiLk1pbi5ZLCBhYWJiLk1pbi5YICogY29zWSArIGFhYmIuTWF4LlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDMKICAgICAgICAgICAgVmVjdG9yMyBmcmQgPSBuZXcgVmVjdG9yMyhhYWJiLk1heC5aICogY29zWSAtIGFhYmIuTWluLlggKiBzaW5ZLCBhYWJiLk1heC5ZLCBhYWJiLk1pbi5YICogY29zWSArIGFhYmIuTWF4LlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDQKICAgICAgICAgICAgVmVjdG9yMyBicmIgPSBuZXcgVmVjdG9yMyhhYWJiLk1pbi5aICogY29zWSAtIGFhYmIuTWluLlggKiBzaW5ZLCBhYWJiLk1heC5ZLCBhYWJiLk1pbi5YICogY29zWSArIGFhYmIuTWluLlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDUKICAgICAgICAgICAgVmVjdG9yMyBibHQgPSBuZXcgVmVjdG9yMyhhYWJiLk1pbi5aICogY29zWSAtIGFhYmIuTWF4LlggKiBzaW5ZLCBhYWJiLk1heC5ZLCBhYWJiLk1heC5YICogY29zWSArIGFhYmIuTWluLlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDYKICAgICAgICAgICAgVmVjdG9yMyBmbHQgPSBuZXcgVmVjdG9yMyhhYWJiLk1heC5aICogY29zWSAtIGFhYmIuTWF4LlggKiBzaW5ZLCBhYWJiLk1heC5ZLCBhYWJiLk1heC5YICogY29zWSArIGFhYmIuTWF4LlogKiBzaW5ZKSArIG1fUG9zaXRpb247IC8vIDcKCiAgICAgICAgICAgICNyZWdpb24gV29ybGRUb1NjcmVlbgogICAgICAgICAgICBpZiAoIVdvcmxkVG9TY3JlZW4oZmxkLCBvdXQgZmxkKSB8fCAhV29ybGRUb1NjcmVlbihicnQsIG91dCBicnQpCiAgICAgICAgICAgICAgICB8fCAhV29ybGRUb1NjcmVlbihibGQsIG91dCBibGQpIHx8ICFXb3JsZFRvU2NyZWVuKGZydCwgb3V0IGZydCkKICAgICAgICAgICAgICAgIHx8ICFXb3JsZFRvU2NyZWVuKGZyZCwgb3V0IGZyZCkgfHwgIVdvcmxkVG9TY3JlZW4oYnJiLCBvdXQgYnJiKQogICAgICAgICAgICAgICAgfHwgIVdvcmxkVG9TY3JlZW4oYmx0LCBvdXQgYmx0KSB8fCAhV29ybGRUb1NjcmVlbihmbHQsIG91dCBmbHQpKQogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICAjZW5kcmVnaW9uCgogICAgICAgICAgICAjcmVnaW9uIERyYXdMaW5lcwogICAgICAgICAgICBEcmF3TGluZShmbGQsIGJydCwgY29sb3IpOwogICAgICAgICAgICBEcmF3TGluZShicmIsIGJsdCwgY29sb3IpOwogICAgICAgICAgICBEcmF3TGluZShmbGQsIGJyYiwgY29sb3IpOwogICAgICAgICAgICBEcmF3TGluZShicnQsIGJsdCwgY29sb3IpOwoKICAgICAgICAgICAgRHJhd0xpbmUoZnJ0LCBibGQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJkLCBmbHQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoZnJ0LCBmcmQsIGNvbG9yKTsKICAgICAgICAgICAgRHJhd0xpbmUoYmxkLCBmbHQsIGNvbG9yKTsKCiAgICAgICAgICAgIERyYXdMaW5lKGZydCwgZmxkLCBjb2xvcik7CiAgICAgICAgICAgIERyYXdMaW5lKGZyZCwgYnJiLCBjb2xvcik7CiAgICAgICAgICAgIERyYXdMaW5lKGJydCwgYmxkLCBjb2xvcik7CiAgICAgICAgICAgIERyYXdMaW5lKGJsdCwgZmx0LCBjb2xvcik7CiAgICAgICAgICAgICNlbmRyZWdpb24KICAgICAgICB9CgogICAgICAgIHByaXZhdGUgdm9pZCBEcmF3TWVudShpbnQgWCwgaW50IFkpCiAgICAgICAgewogICAgICAgICAgICBDb2xvciBzZWxlY3RlZENvbG9yID0gbmV3IENvbG9yKDI1NSwgMjE0LCAwLCAyNTUpOwogICAgICAgICAgICBEcmF3VGV4dChYLCBZLCAiRjU6IEVTUCBCb3giLCBFU1BfQm94ID8gc2VsZWN0ZWRDb2xvciA6IENvbG9yLldoaXRlLCB0cnVlLCBmb250U21hbGwpOwogICAgICAgICAgICBEcmF3VGV4dChYICsgMTAwLCBZLCAiRjY6IEVTUCBCb25lIiwgRVNQX0JvbmUgPyBzZWxlY3RlZENvbG9yIDogQ29sb3IuV2hpdGUsIHRydWUsIGZvbnRTbWFsbCk7CiAgICAgICAgICAgIERyYXdUZXh0KFggKyAyMDAsIFksICJGNzogRVNQIEhlYWx0aCIsIEVTUF9IZWFsdGggPyBzZWxlY3RlZENvbG9yIDogQ29sb3IuV2hpdGUsIHRydWUsIGZvbnRTbWFsbCk7CiAgICAgICAgICAgIERyYXdUZXh0KFggKyAzMTAsIFksICJGODogRVNQIERpc3RhbmNlIiwgRVNQX0Rpc3RhbmNlID8gc2VsZWN0ZWRDb2xvciA6IENvbG9yLldoaXRlLCB0cnVlLCBmb250U21hbGwpOwogICAgICAgICAgICBEcmF3VGV4dChYICsgNDMwLCBZLCAiRjk6IEVTUCBWZWhpY2xlIiwgRVNQX1ZlaGljbGUgPyBzZWxlY3RlZENvbG9yIDogQ29sb3IuV2hpdGUsIHRydWUsIGZvbnRTbWFsbCk7CiAgICAgICAgfQoKICAgICAgICBwcml2YXRlIHZvaWQgRHJhd1dhcm4oaW50IFgsIGludCBZLCBpbnQgVywgaW50IEgpCiAgICAgICAgewogICAgICAgICAgICBSb3VuZGVkUmVjdGFuZ2xlIHJlY3QgPSBuZXcgUm91bmRlZFJlY3RhbmdsZSgpOwogICAgICAgICAgICByZWN0LlJhZGl1c1ggPSA0OwogICAgICAgICAgICByZWN0LlJhZGl1c1kgPSA0OwogICAgICAgICAgICByZWN0LlJlY3QgPSBuZXcgUmVjdGFuZ2xlRihYLCBZLCBXLCBIKTsKCiAgICAgICAgICAgIHNvbGlkQ29sb3JCcnVzaC5Db2xvciA9IG5ldyBDb2xvcigxOTYsIDI2LCAzMSwgMjEwKTsKICAgICAgICAgICAgZGV2aWNlLkZpbGxSb3VuZGVkUmVjdGFuZ2xlKHJlZiByZWN0LCBzb2xpZENvbG9yQnJ1c2gpOwoKICAgICAgICAgICAgRHJhd1RleHQoWCArIDIwLCBZICsgNSwgIlNwZWN0YXRvciBvbiB0aGUgc2VydmVyLiIsIENvbG9yLldoaXRlLCB0cnVlKTsKICAgICAgICAgICAgRHJhd1RleHQoWCArIDIwLCBZICsgMjUsICJXYXRjaGluZyBZb3UhIiwgQ29sb3IuV2hpdGUsIHRydWUpOwogICAgICAgIH0gCiAgICAgICAgI2VuZHJlZ2lvbgogICAgfQp9Cg==