#include <includes.h>
//AARRGGBB
struct ButtonColor
{
DWORD button;
DWORD border;
DWORD text;
ButtonColor(){}
~ButtonColor(){}
ButtonColor(DWORD color_button,DWORD color_border,DWORD color_text)
: button(color_button),border(color_border),text(color_text)
{}
};
class Button
{
public:
typedef std::function<void(Button*)> Callback;
std::string text_;
ButtonColor appearance_;
ButtonColor highlighted_;
ButtonColor mousedown_;
bool clickable_;
bool highlight_;
unsigned short vkkey_;
int fontid_;
Callback * OnButtonClicked_;
Button()
{
OnButtonClicked_ = NULL;
}
~Button()
{
if(OnButtonClicked_)
delete OnButtonClicked_;
}
Button(std::string button_text,ButtonColor &appearance, ButtonColor &highlighted, ButtonColor &mousedown, bool clickable, bool highlight, int fontid = 1, unsigned short vkkey = VK_LBUTTON)
: text_(button_text), appearance_(appearance), highlighted_(highlighted), clickable_(clickable), highlight_(highlight), mousedown_(mousedown), vkkey_(vkkey), fontid_(fontid)
{
OnButtonClicked_ = NULL;
}
void SetInfo(std::string button_text,ButtonColor &appearance, ButtonColor &highlighted, ButtonColor &mousedown, bool clickable, bool highlight, int fontid = 1, unsigned short vkkey = VK_LBUTTON)
{
text_.assign(button_text);
appearance_ = appearance;
highlighted_ = highlighted;
clickable_ = clickable;
highlight_ = highlight;
mousedown_ = mousedown;
vkkey_ = vkkey;
fontid_ = fontid;
}
void SetCallback(std::function<void(Button*)> &callback)
{
if(OnButtonClicked_)
delete OnButtonClicked_;
OnButtonClicked_ = NULL;
OnButtonClicked_ = new Callback(callback);
}
float Lenght()
{
return DirectXFont::Access(fontid_)->DrawLength(text_.c_str());
}
float Height()
{
return DirectXFont::Access(fontid_)->DrawHeight();
}
bool IsCursorOnThis(float btn_x, float btn_y, float btn_w, float btn_h)
{
return IsPointInArea(cursorPos.x,cursorPos.y,btn_x,btn_y,btn_w,btn_h);
}
void Display(float btn_x, float btn_y, float btn_w, float btn_h)
{
if(!IsPointInArea(cursorPos.x,cursorPos.y,btn_x,btn_y,btn_w,btn_h))
{
render->D3DBoxBorder(btn_x,btn_y,btn_w,btn_h,appearance_.border,appearance_.button);
DirectXFont::Access(fontid_)->Print(btn_x+((btn_w-Lenght())/2.0f),btn_y+((btn_h-Height())/2.0f),appearance_.text,text_.c_str(),true);
return;
}
if(!clickable_)
{
render->D3DBoxBorder(btn_x,btn_y,btn_w,btn_h,(highlight_)? highlighted_.border : appearance_.border,(highlight_)? highlighted_.button : appearance_.button);
DirectXFont::Access(fontid_)->Print(btn_x+((btn_w-Lenght())/2.0f),btn_y+((btn_h-Height())/2.0f),(highlight_)? highlighted_.text : appearance_.text,text_.c_str(),true);
return;
}
if(!OldKeys(vkkey_).Down)
{
render->D3DBoxBorder(btn_x,btn_y,btn_w,btn_h,(highlight_)? highlighted_.border : appearance_.border,(highlight_)? highlighted_.button : appearance_.button);
DirectXFont::Access(fontid_)->Print(btn_x+((btn_w-Lenght())/2.0f),btn_y+((btn_h-Height())/2.0f),(highlight_)? highlighted_.text : appearance_.text,text_.c_str(),true);
return;
}
if(!Keys(vkkey_).Released)
{
render->D3DBoxBorder(btn_x,btn_y,btn_w,btn_h, mousedown_.border,mousedown_.button);
DirectXFont::Access(fontid_)->Print(btn_x+((btn_w-Lenght())/2.0f),btn_y+((btn_h-Height())/2.0f), mousedown_.text,text_.c_str(),true);
return;
}
if(OnButtonClicked_)
(*OnButtonClicked_)(this);
return;
}
};
class Menu
{
public:
std::vector<Button*> Buttons_;
float pos_top_;
float pos_left_;
float spacing_;
float width_;
float height_;
//int maxcolumns_;
DWORD BoxColor;
DWORD BorderColor;
std::string name_;
Menu()
{
pos_top_ = 0.0f;
pos_left_ = 0.0f;
spacing_ = 5.0f;
width_ = 0.0f;
height_ = 0.0f;
//maxcolumns_ = 1;
BoxColor = 0xFF330088;
BorderColor = 0xFF338800;
}
~Menu()
{
for(unsigned int i = 0; i < Buttons_.size(); ++i)
delete Buttons_[i];
Buttons_.clear();
}
void SetupWidth()
{
width_ = 0.0f;
height_ = 0.0f;
for(unsigned int i = 0; i < Buttons_.size(); ++i)
{
if(width_ < Buttons_[i]->Lenght())
{
width_ = Buttons_[i]->Lenght();
}
if(height_ < Buttons_[i]->Height())
{
height_ = Buttons_[i]->Height();
}
}
}
void AddButton(Button* button)
{
Buttons_.push_back(button);
SetupWidth();
}
void RemoveButton(Button* button)
{
for(unsigned int i = 0; i < Buttons_.size(); ++i)
{
if(Buttons_[i] == button)
{
delete Buttons_[i];
Buttons_.erase(Buttons_.begin()+i);
}
}
SetupWidth();
}
float Width(bool horizontal = false)
{
if(!horizontal)
return (width_ + (spacing_ * 4.0f));
if(Buttons_.empty())
return spacing_;
return spacing_ + ((width_ + (3.0f * spacing_)) * ((float)Buttons_.size()));
}
float Height(bool horizontal = false)
{
if(horizontal)
return (3.0f * spacing_) + height_;
if(Buttons_.empty())
return spacing_;
return spacing_ + (((float)Buttons_.size())*spacing_)+((spacing_ + height_)*((float)Buttons_.size()));
}
void Process(bool horizontal = false, bool central = true)
{
if(Buttons_.empty())
return;
if(central)
{
Pos((((float)ScreenX)/2.0f)-(Width(horizontal)/2.0f),(((float)ScreenY)/2.0f)-(Height(horizontal)/2.0f));
}
if(!horizontal)
{
render->D3DBoxBorder(pos_left_,pos_top_,(width_ + (spacing_ * 4.0f)),spacing_ + (((float)Buttons_.size())*spacing_)+((spacing_ + height_)*((float)Buttons_.size())), BorderColor,BoxColor);
for(unsigned int i = 0; i < Buttons_.size(); ++i)
{
Buttons_[i]->Display(pos_left_ + spacing_,pos_top_ + spacing_ + spacing_*((float)i) + ((spacing_ + height_)*(float)i),(width_ + (2.0f * spacing_)),height_+spacing_);
}
}
else
{
render->D3DBoxBorder(pos_left_,pos_top_,spacing_ + ((width_ + (3.0f * spacing_)) * ((float)Buttons_.size())),(3.0f * spacing_) + height_, BorderColor,BoxColor);
for(unsigned int i = 0; i < Buttons_.size(); ++i)
{
Buttons_[i]->Display(pos_left_ + spacing_ + ((width_ + (3.0f * spacing_)) * ((float)i)),pos_top_ + spacing_ ,(width_ + (2.0f * spacing_)),height_+spacing_);
}
}
}
void SetCallback(std::function<void(Button*)> &callback)
{
for(unsigned int i = 0; i < Buttons_.size(); ++i)
{
Buttons_[i]->SetCallback(callback);
}
}
void Pos(float x, float y)
{
pos_left_ = x;
pos_top_ = y;
}
void Colors(DWORD border,DWORD background)
{
BorderColor = border;
BoxColor = background;
}
};
I2luY2x1ZGUgPGluY2x1ZGVzLmg+CgovL0FBUlJHR0JCCnN0cnVjdCBCdXR0b25Db2xvcgp7CiAgICBEV09SRCBidXR0b247CglEV09SRCBib3JkZXI7CglEV09SRCB0ZXh0OwoJQnV0dG9uQ29sb3IoKXt9Cgl+QnV0dG9uQ29sb3IoKXt9CglCdXR0b25Db2xvcihEV09SRCBjb2xvcl9idXR0b24sRFdPUkQgY29sb3JfYm9yZGVyLERXT1JEIGNvbG9yX3RleHQpCgkJOiBidXR0b24oY29sb3JfYnV0dG9uKSxib3JkZXIoY29sb3JfYm9yZGVyKSx0ZXh0KGNvbG9yX3RleHQpCgl7fQp9OwoKY2xhc3MgQnV0dG9uCnsKcHVibGljOgoJdHlwZWRlZiBzdGQ6OmZ1bmN0aW9uPHZvaWQoQnV0dG9uKik+IENhbGxiYWNrOwoJc3RkOjpzdHJpbmcgdGV4dF87CglCdXR0b25Db2xvciBhcHBlYXJhbmNlXzsKCUJ1dHRvbkNvbG9yIGhpZ2hsaWdodGVkXzsKCUJ1dHRvbkNvbG9yIG1vdXNlZG93bl87Cglib29sIGNsaWNrYWJsZV87Cglib29sIGhpZ2hsaWdodF87Cgl1bnNpZ25lZCBzaG9ydCB2a2tleV87CglpbnQgZm9udGlkXzsKCUNhbGxiYWNrICogT25CdXR0b25DbGlja2VkXzsKCUJ1dHRvbigpCgl7CgkJT25CdXR0b25DbGlja2VkXyA9IE5VTEw7Cgl9Cgl+QnV0dG9uKCkKCXsKCQlpZihPbkJ1dHRvbkNsaWNrZWRfKQoJCQlkZWxldGUgT25CdXR0b25DbGlja2VkXzsKCX0KCUJ1dHRvbihzdGQ6OnN0cmluZyBidXR0b25fdGV4dCxCdXR0b25Db2xvciAmYXBwZWFyYW5jZSwgQnV0dG9uQ29sb3IgJmhpZ2hsaWdodGVkLCBCdXR0b25Db2xvciAmbW91c2Vkb3duLCBib29sIGNsaWNrYWJsZSwgYm9vbCBoaWdobGlnaHQsIGludCBmb250aWQgPSAxLCB1bnNpZ25lZCBzaG9ydCB2a2tleSA9IFZLX0xCVVRUT04pCgkJOiB0ZXh0XyhidXR0b25fdGV4dCksIGFwcGVhcmFuY2VfKGFwcGVhcmFuY2UpLCBoaWdobGlnaHRlZF8oaGlnaGxpZ2h0ZWQpLCBjbGlja2FibGVfKGNsaWNrYWJsZSksIGhpZ2hsaWdodF8oaGlnaGxpZ2h0KSwgbW91c2Vkb3duXyhtb3VzZWRvd24pLCB2a2tleV8odmtrZXkpLCBmb250aWRfKGZvbnRpZCkKCXsKCQlPbkJ1dHRvbkNsaWNrZWRfID0gTlVMTDsKCX0KCXZvaWQgU2V0SW5mbyhzdGQ6OnN0cmluZyBidXR0b25fdGV4dCxCdXR0b25Db2xvciAmYXBwZWFyYW5jZSwgQnV0dG9uQ29sb3IgJmhpZ2hsaWdodGVkLCBCdXR0b25Db2xvciAmbW91c2Vkb3duLCBib29sIGNsaWNrYWJsZSwgYm9vbCBoaWdobGlnaHQsIGludCBmb250aWQgPSAxLCB1bnNpZ25lZCBzaG9ydCB2a2tleSA9IFZLX0xCVVRUT04pCgl7CgkJdGV4dF8uYXNzaWduKGJ1dHRvbl90ZXh0KTsKCQlhcHBlYXJhbmNlXyA9IGFwcGVhcmFuY2U7CgkJaGlnaGxpZ2h0ZWRfID0gaGlnaGxpZ2h0ZWQ7CgkJY2xpY2thYmxlXyA9IGNsaWNrYWJsZTsKCQloaWdobGlnaHRfID0gaGlnaGxpZ2h0OwoJCW1vdXNlZG93bl8gPSBtb3VzZWRvd247CgkJdmtrZXlfID0gdmtrZXk7CgkJZm9udGlkXyA9IGZvbnRpZDsKCX0KCXZvaWQgU2V0Q2FsbGJhY2soc3RkOjpmdW5jdGlvbjx2b2lkKEJ1dHRvbiopPiAmY2FsbGJhY2spCgl7CgkJaWYoT25CdXR0b25DbGlja2VkXykKCQkJZGVsZXRlIE9uQnV0dG9uQ2xpY2tlZF87CgkJT25CdXR0b25DbGlja2VkXyA9IE5VTEw7CgkJT25CdXR0b25DbGlja2VkXyA9IG5ldyBDYWxsYmFjayhjYWxsYmFjayk7Cgl9CglmbG9hdCBMZW5naHQoKQoJewoJCXJldHVybiBEaXJlY3RYRm9udDo6QWNjZXNzKGZvbnRpZF8pLT5EcmF3TGVuZ3RoKHRleHRfLmNfc3RyKCkpOwoJfQoJZmxvYXQgSGVpZ2h0KCkKCXsKCQlyZXR1cm4gRGlyZWN0WEZvbnQ6OkFjY2Vzcyhmb250aWRfKS0+RHJhd0hlaWdodCgpOwoJfQoJYm9vbCBJc0N1cnNvck9uVGhpcyhmbG9hdCBidG5feCwgZmxvYXQgYnRuX3ksIGZsb2F0IGJ0bl93LCBmbG9hdCBidG5faCkKCXsKCQlyZXR1cm4gSXNQb2ludEluQXJlYShjdXJzb3JQb3MueCxjdXJzb3JQb3MueSxidG5feCxidG5feSxidG5fdyxidG5faCk7Cgl9Cgl2b2lkIERpc3BsYXkoZmxvYXQgYnRuX3gsIGZsb2F0IGJ0bl95LCBmbG9hdCBidG5fdywgZmxvYXQgYnRuX2gpCgl7CgkJaWYoIUlzUG9pbnRJbkFyZWEoY3Vyc29yUG9zLngsY3Vyc29yUG9zLnksYnRuX3gsYnRuX3ksYnRuX3csYnRuX2gpKQoJCXsKCQkJcmVuZGVyLT5EM0RCb3hCb3JkZXIoYnRuX3gsYnRuX3ksYnRuX3csYnRuX2gsYXBwZWFyYW5jZV8uYm9yZGVyLGFwcGVhcmFuY2VfLmJ1dHRvbik7CgkJCURpcmVjdFhGb250OjpBY2Nlc3MoZm9udGlkXyktPlByaW50KGJ0bl94KygoYnRuX3ctTGVuZ2h0KCkpLzIuMGYpLGJ0bl95KygoYnRuX2gtSGVpZ2h0KCkpLzIuMGYpLGFwcGVhcmFuY2VfLnRleHQsdGV4dF8uY19zdHIoKSx0cnVlKTsKCQkJcmV0dXJuOwoJCX0KCQlpZighY2xpY2thYmxlXykKCQl7CgkJCXJlbmRlci0+RDNEQm94Qm9yZGVyKGJ0bl94LGJ0bl95LGJ0bl93LGJ0bl9oLChoaWdobGlnaHRfKT8gaGlnaGxpZ2h0ZWRfLmJvcmRlciA6IGFwcGVhcmFuY2VfLmJvcmRlciwoaGlnaGxpZ2h0Xyk/IGhpZ2hsaWdodGVkXy5idXR0b24gOiBhcHBlYXJhbmNlXy5idXR0b24pOwoJCQlEaXJlY3RYRm9udDo6QWNjZXNzKGZvbnRpZF8pLT5QcmludChidG5feCsoKGJ0bl93LUxlbmdodCgpKS8yLjBmKSxidG5feSsoKGJ0bl9oLUhlaWdodCgpKS8yLjBmKSwoaGlnaGxpZ2h0Xyk/IGhpZ2hsaWdodGVkXy50ZXh0IDogYXBwZWFyYW5jZV8udGV4dCx0ZXh0Xy5jX3N0cigpLHRydWUpOwoJCQlyZXR1cm47CgkJfQoJCWlmKCFPbGRLZXlzKHZra2V5XykuRG93bikKCQl7CgkJCXJlbmRlci0+RDNEQm94Qm9yZGVyKGJ0bl94LGJ0bl95LGJ0bl93LGJ0bl9oLChoaWdobGlnaHRfKT8gaGlnaGxpZ2h0ZWRfLmJvcmRlciA6IGFwcGVhcmFuY2VfLmJvcmRlciwoaGlnaGxpZ2h0Xyk/IGhpZ2hsaWdodGVkXy5idXR0b24gOiBhcHBlYXJhbmNlXy5idXR0b24pOwoJCQlEaXJlY3RYRm9udDo6QWNjZXNzKGZvbnRpZF8pLT5QcmludChidG5feCsoKGJ0bl93LUxlbmdodCgpKS8yLjBmKSxidG5feSsoKGJ0bl9oLUhlaWdodCgpKS8yLjBmKSwoaGlnaGxpZ2h0Xyk/IGhpZ2hsaWdodGVkXy50ZXh0IDogYXBwZWFyYW5jZV8udGV4dCx0ZXh0Xy5jX3N0cigpLHRydWUpOwkKCQkJcmV0dXJuOwoJCX0KCQlpZighS2V5cyh2a2tleV8pLlJlbGVhc2VkKQoJCXsKCQkJcmVuZGVyLT5EM0RCb3hCb3JkZXIoYnRuX3gsYnRuX3ksYnRuX3csYnRuX2gsIG1vdXNlZG93bl8uYm9yZGVyLG1vdXNlZG93bl8uYnV0dG9uKTsKCQkJRGlyZWN0WEZvbnQ6OkFjY2Vzcyhmb250aWRfKS0+UHJpbnQoYnRuX3grKChidG5fdy1MZW5naHQoKSkvMi4wZiksYnRuX3krKChidG5faC1IZWlnaHQoKSkvMi4wZiksIG1vdXNlZG93bl8udGV4dCx0ZXh0Xy5jX3N0cigpLHRydWUpOwoJCQlyZXR1cm47CgkJfQoJCWlmKE9uQnV0dG9uQ2xpY2tlZF8pCgkJCSgqT25CdXR0b25DbGlja2VkXykodGhpcyk7CQoJCXJldHVybjsKCX0KfTsKCmNsYXNzIE1lbnUKewpwdWJsaWM6CglzdGQ6OnZlY3RvcjxCdXR0b24qPiBCdXR0b25zXzsKCWZsb2F0IHBvc190b3BfOwoJZmxvYXQgcG9zX2xlZnRfOwoJZmxvYXQgc3BhY2luZ187CglmbG9hdCB3aWR0aF87CglmbG9hdCBoZWlnaHRfOwoJLy9pbnQgbWF4Y29sdW1uc187CglEV09SRCBCb3hDb2xvcjsKCURXT1JEIEJvcmRlckNvbG9yOwoKCXN0ZDo6c3RyaW5nIG5hbWVfOwoJTWVudSgpCgl7CgkJcG9zX3RvcF8gPSAwLjBmOwoJCXBvc19sZWZ0XyA9IDAuMGY7CgkJc3BhY2luZ18gPSA1LjBmOwoJCXdpZHRoXyA9IDAuMGY7CgkJaGVpZ2h0XyA9IDAuMGY7CgkJLy9tYXhjb2x1bW5zXyA9IDE7CgkJQm94Q29sb3IgPSAweEZGMzMwMDg4OwoJCUJvcmRlckNvbG9yID0gMHhGRjMzODgwMDsKCX0KCX5NZW51KCkKCXsKCQlmb3IodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgQnV0dG9uc18uc2l6ZSgpOyArK2kpCgkJCWRlbGV0ZSBCdXR0b25zX1tpXTsKCQlCdXR0b25zXy5jbGVhcigpOwoJfQoJdm9pZCBTZXR1cFdpZHRoKCkKCXsKCQl3aWR0aF8gPSAwLjBmOwoJCWhlaWdodF8gPSAwLjBmOwoJCWZvcih1bnNpZ25lZCBpbnQgaSA9IDA7IGkgPCBCdXR0b25zXy5zaXplKCk7ICsraSkKCQl7CgkJCWlmKHdpZHRoXyA8IEJ1dHRvbnNfW2ldLT5MZW5naHQoKSkKCQkJewoJCQkJd2lkdGhfID0gQnV0dG9uc19baV0tPkxlbmdodCgpOwoJCQl9CgkJCWlmKGhlaWdodF8gPCBCdXR0b25zX1tpXS0+SGVpZ2h0KCkpCgkJCXsKCQkJCWhlaWdodF8gPSBCdXR0b25zX1tpXS0+SGVpZ2h0KCk7CgkJCX0KCQl9Cgl9Cgl2b2lkIEFkZEJ1dHRvbihCdXR0b24qIGJ1dHRvbikKCXsKCQlCdXR0b25zXy5wdXNoX2JhY2soYnV0dG9uKTsKCQlTZXR1cFdpZHRoKCk7Cgl9Cgl2b2lkIFJlbW92ZUJ1dHRvbihCdXR0b24qIGJ1dHRvbikKCXsKCQlmb3IodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgQnV0dG9uc18uc2l6ZSgpOyArK2kpCgkJewoJCQlpZihCdXR0b25zX1tpXSA9PSBidXR0b24pCgkJCXsKCQkJCWRlbGV0ZSBCdXR0b25zX1tpXTsKCQkJCUJ1dHRvbnNfLmVyYXNlKEJ1dHRvbnNfLmJlZ2luKCkraSk7CgkJCX0KCQl9CgkJU2V0dXBXaWR0aCgpOwoJfQoJZmxvYXQgV2lkdGgoYm9vbCBob3Jpem9udGFsID0gZmFsc2UpCgl7CgkJaWYoIWhvcml6b250YWwpCgkJCXJldHVybiAod2lkdGhfICsgKHNwYWNpbmdfICogNC4wZikpOwoJCWlmKEJ1dHRvbnNfLmVtcHR5KCkpCgkJCXJldHVybiBzcGFjaW5nXzsKCQlyZXR1cm4gc3BhY2luZ18gKyAoKHdpZHRoXyArICgzLjBmICogc3BhY2luZ18pKSAqICgoZmxvYXQpQnV0dG9uc18uc2l6ZSgpKSk7Cgl9CglmbG9hdCBIZWlnaHQoYm9vbCBob3Jpem9udGFsID0gZmFsc2UpCgl7CgkJaWYoaG9yaXpvbnRhbCkKCQkJcmV0dXJuICgzLjBmICogc3BhY2luZ18pICsgaGVpZ2h0XzsKCQlpZihCdXR0b25zXy5lbXB0eSgpKQoJCQlyZXR1cm4gc3BhY2luZ187CgkJcmV0dXJuIHNwYWNpbmdfICsgKCgoZmxvYXQpQnV0dG9uc18uc2l6ZSgpKSpzcGFjaW5nXykrKChzcGFjaW5nXyArIGhlaWdodF8pKigoZmxvYXQpQnV0dG9uc18uc2l6ZSgpKSk7Cgl9Cgl2b2lkIFByb2Nlc3MoYm9vbCBob3Jpem9udGFsID0gZmFsc2UsIGJvb2wgY2VudHJhbCA9IHRydWUpCgl7CgkJaWYoQnV0dG9uc18uZW1wdHkoKSkKCQkJcmV0dXJuOwoJCWlmKGNlbnRyYWwpCgkJewoJCQlQb3MoKCgoZmxvYXQpU2NyZWVuWCkvMi4wZiktKFdpZHRoKGhvcml6b250YWwpLzIuMGYpLCgoKGZsb2F0KVNjcmVlblkpLzIuMGYpLShIZWlnaHQoaG9yaXpvbnRhbCkvMi4wZikpOwoJCX0KCQlpZighaG9yaXpvbnRhbCkKCQl7CgkJCXJlbmRlci0+RDNEQm94Qm9yZGVyKHBvc19sZWZ0Xyxwb3NfdG9wXywod2lkdGhfICsgKHNwYWNpbmdfICogNC4wZikpLHNwYWNpbmdfICsgKCgoZmxvYXQpQnV0dG9uc18uc2l6ZSgpKSpzcGFjaW5nXykrKChzcGFjaW5nXyArIGhlaWdodF8pKigoZmxvYXQpQnV0dG9uc18uc2l6ZSgpKSksIEJvcmRlckNvbG9yLEJveENvbG9yKTsKCQkJZm9yKHVuc2lnbmVkIGludCBpID0gMDsgaSA8IEJ1dHRvbnNfLnNpemUoKTsgKytpKQoJCQl7CQoJCQkJQnV0dG9uc19baV0tPkRpc3BsYXkocG9zX2xlZnRfICsgc3BhY2luZ18scG9zX3RvcF8gKyBzcGFjaW5nXyArIHNwYWNpbmdfKigoZmxvYXQpaSkgKyAoKHNwYWNpbmdfICsgaGVpZ2h0XykqKGZsb2F0KWkpLCh3aWR0aF8gKyAoMi4wZiAqIHNwYWNpbmdfKSksaGVpZ2h0XytzcGFjaW5nXyk7CgkJCX0KCQl9CgkJZWxzZQoJCXsKCQkJcmVuZGVyLT5EM0RCb3hCb3JkZXIocG9zX2xlZnRfLHBvc190b3BfLHNwYWNpbmdfICsgKCh3aWR0aF8gKyAoMy4wZiAqIHNwYWNpbmdfKSkgKiAoKGZsb2F0KUJ1dHRvbnNfLnNpemUoKSkpLCgzLjBmICogc3BhY2luZ18pICsgaGVpZ2h0XywgQm9yZGVyQ29sb3IsQm94Q29sb3IpOwoJCQlmb3IodW5zaWduZWQgaW50IGkgPSAwOyBpIDwgQnV0dG9uc18uc2l6ZSgpOyArK2kpCgkJCXsJCgkJCQlCdXR0b25zX1tpXS0+RGlzcGxheShwb3NfbGVmdF8gKyBzcGFjaW5nXyArICgod2lkdGhfICsgKDMuMGYgKiBzcGFjaW5nXykpICogKChmbG9hdClpKSkscG9zX3RvcF8gKyBzcGFjaW5nXyAsKHdpZHRoXyArICgyLjBmICogc3BhY2luZ18pKSxoZWlnaHRfK3NwYWNpbmdfKTsKCQkJfQoJCX0KCX0KCXZvaWQgU2V0Q2FsbGJhY2soc3RkOjpmdW5jdGlvbjx2b2lkKEJ1dHRvbiopPiAmY2FsbGJhY2spCgl7CgkJZm9yKHVuc2lnbmVkIGludCBpID0gMDsgaSA8IEJ1dHRvbnNfLnNpemUoKTsgKytpKQoJCXsKCQkJQnV0dG9uc19baV0tPlNldENhbGxiYWNrKGNhbGxiYWNrKTsKCQl9Cgl9Cgl2b2lkIFBvcyhmbG9hdCB4LCBmbG9hdCB5KQoJewoJCXBvc19sZWZ0XyA9IHg7CgkJcG9zX3RvcF8gPSB5OwoJfQoJdm9pZCBDb2xvcnMoRFdPUkQgYm9yZGVyLERXT1JEIGJhY2tncm91bmQpCgl7CgkJQm9yZGVyQ29sb3IgPSBib3JkZXI7CgkJQm94Q29sb3IgPSBiYWNrZ3JvdW5kOwoJfQp9Ow==