// ConvexSquare.cpp : アプリケーションのエントリ ポイントを定義します。
//
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーからほとんど使用されていない部分を除外する
// Windows ヘッダー ファイル
#include <windows.h>
// C ランタイム ヘッダー ファイル
#include <tchar.h>
#include <iterator>
#include <algorithm>
#include <vector>
std::vector<int> v{ 136, 577, 110, 927, 472, 199, 157, 808, 388, 598, 94, 31, 388, 157, 325, 409, 787, 897, 850, 598 };
struct vec2d {
int x, y;
vec2d& operator=(const vec2d& ref) {
x = ref.x;
y = ref.y;
return *this;
}
bool operator==(const vec2d& ref) const {
return x == ref.x && y == ref.y;
}
bool operator!=(const vec2d& ref) const {
return !operator==(ref);
}
vec2d operator-(const vec2d& ref) const {
return { x - ref.x, y - ref.y };
}
vec2d operator+(const vec2d& ref) const {
return { x + ref.x, y + ref.y };
}
int dot(const vec2d& ref) const {
return x * ref.y + y * ref.x;
}
int cross(const vec2d& ref) const {
return x * ref.y - ref.x * y;
}
};
using Vertices = std::vector<vec2d>;
auto getVertices()
{
auto i = std::begin(v);
auto e = i; std::advance(e, std::size(v) - std::size(v) % 2);
Vertices result;
while (i != e) {
result.push_back({ *i, *std::next(i) });
std::advance(i, 2);
}
return result;
}
int findStartPoint(const Vertices& vertices)
{
auto p = 0;
auto x = vertices[p].x, y = vertices[p].y;
for (size_t i = 0; i < std::size(vertices); i++) {
auto diff = y - vertices[i].y;
if (diff > 0) {
y = vertices[i].y;
x = vertices[i].x;
p = i;
}
else if (diff == 0 && x > vertices[i].x) {
x = vertices[i].x;
p = i;
}
}
return p;
}
auto getConvexHull(const Vertices& vertices)
{
Vertices result;
if (std::size(vertices) == 0) {
return result;
}
auto a = findStartPoint(vertices);
for (;;) {
result.push_back(vertices[a]);
auto b = 0;
for (size_t i = 1; i < std::size(vertices); i++) {
auto c = i;
if (vertices[b] == vertices[a]) {
b = c;
}
else {
vec2d A = vertices[a];
vec2d B = vertices[b];
vec2d C = vertices[c];
int v = (B - A).cross(C - A);
if (v > 0) {
b = c;
}
}
}
a = b;
if (result[0] == vertices[a]) {
break;
}
}
return result;
}
auto getInclusionCircle(const Vertices& vertices)
{
Vertices result;
return result;
}
// グローバル変数:
HINSTANCE hInst; // 現在のインターフェイス
WCHAR szTitle[]=_T("ConvexSquare"); // タイトル バーのテキスト
WCHAR szWindowClass[]=_T("CONVEXSQUARE"); // メイン ウィンドウ クラス名
// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: ここにコードを挿入してください。
auto vertices = getVertices();
auto convex_hull = getConvexHull(vertices);
// グローバル文字列を初期化する
MyRegisterClass(hInstance);
// アプリケーション初期化の実行:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
MSG msg;
// メイン メッセージ ループ:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
//
// 関数: MyRegisterClass()
//
// 目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
return RegisterClassExW(&wcex);
}
//
// 関数: InitInstance(HINSTANCE, int)
//
// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します
//
// コメント:
//
// この関数で、グローバル変数でインスタンス ハンドルを保存し、
// メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // グローバル変数にインスタンス ハンドルを格納する
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: メイン ウィンドウのメッセージを処理します。
//
// WM_COMMAND - アプリケーション メニューの処理
// WM_PAINT - メイン ウィンドウを描画する
// WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
v.push_back({ x });
v.push_back({ y });
::InvalidateRect(hWnd, nullptr, true);
}
break;
case WM_RBUTTONDOWN:
{
v.clear();
::InvalidateRect(hWnd, nullptr, true);
}
break;
case WM_MBUTTONDOWN:
{
std::vector<int> tmp{ 136, 577, 110, 927, 472, 199, 157, 808, 388, 598, 94, 31, 388, 157, 325, 409, 787, 897, 850, 598 };
v.swap(tmp);
::InvalidateRect(hWnd, nullptr, true);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: HDC を使用する描画コードをここに追加してください...
::Rectangle(hdc, 0, 0, 999, 999);
{
Vertices vertices = getVertices();
for (auto& v : vertices) {
::Rectangle(hdc, v.x - 1, v.y - 1, v.x + 1, v.y + 1);
}
}
{
Vertices vertices = getConvexHull(getVertices());
if (std::size(vertices) > 0) {
{
for (size_t i = 0; i < std::size(vertices); i++) {
char txt[255];
sprintf_s(txt, 255, "%zu", i);
::TextOutA(hdc, vertices[i].x, vertices[i].y, txt, strlen(txt));
}
}
{
HBRUSH red = ::CreateSolidBrush(RGB(255, 0, 0));
HGDIOBJ brush = ::SelectObject(hdc, red);
HGDIOBJ pen = ::SelectObject(hdc, ::GetStockObject(NULL_PEN));
for (auto& v : vertices) {
::Rectangle(hdc, v.x - 2, v.y - 2, v.x + 2, v.y + 2);
}
::SelectObject(hdc, pen);
::SelectObject(hdc, brush);
::DeleteObject(red);
}
{
auto i = std::begin(vertices);
auto e = std::end(vertices);
::MoveToEx(hdc, i->x, i->y, nullptr);
while (i != e) {
auto to = std::next(i);
if (to == e)
to = std::begin(vertices);
::LineTo(hdc, to->x, to->y);
i++;
}
}
}
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Ly8gQ29udmV4U3F1YXJlLmNwcCA6IOOCouODl+ODquOCseODvOOCt+ODp+ODs+OBruOCqOODs+ODiOODqiDjg53jgqTjg7Pjg4jjgpLlrprnvqnjgZfjgb7jgZnjgIIKLy8KCiNkZWZpbmUgV0lOMzJfTEVBTl9BTkRfTUVBTiAgICAgICAgICAgICAvLyBXaW5kb3dzIOODmOODg+ODgOODvOOBi+OCieOBu+OBqOOCk+OBqeS9v+eUqOOBleOCjOOBpuOBhOOBquOBhOmDqOWIhuOCkumZpOWkluOBmeOCiwovLyBXaW5kb3dzIOODmOODg+ODgOODvCDjg5XjgqHjgqTjg6sKI2luY2x1ZGUgPHdpbmRvd3MuaD4KLy8gQyDjg6njg7Pjgr/jgqTjg6Ag44OY44OD44OA44O8IOODleOCoeOCpOODqwojaW5jbHVkZSA8dGNoYXIuaD4KCiNpbmNsdWRlIDxpdGVyYXRvcj4KI2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPHZlY3Rvcj4KCnN0ZDo6dmVjdG9yPGludD4gdnsgMTM2LCA1NzcsIDExMCwgOTI3LCA0NzIsIDE5OSwgMTU3LCA4MDgsIDM4OCwgNTk4LCA5NCwgMzEsIDM4OCwgMTU3LCAzMjUsIDQwOSwgNzg3LCA4OTcsIDg1MCwgNTk4IH07CgpzdHJ1Y3QgdmVjMmQgewoJaW50IHgsIHk7CgoJdmVjMmQmIG9wZXJhdG9yPShjb25zdCB2ZWMyZCYgcmVmKSB7CgkJeCA9IHJlZi54OwoJCXkgPSByZWYueTsKCQlyZXR1cm4gKnRoaXM7Cgl9CgoJYm9vbCBvcGVyYXRvcj09KGNvbnN0IHZlYzJkJiByZWYpIGNvbnN0IHsKCQlyZXR1cm4geCA9PSByZWYueCAmJiB5ID09IHJlZi55OwoJfQoKCWJvb2wgb3BlcmF0b3IhPShjb25zdCB2ZWMyZCYgcmVmKSBjb25zdCB7CgkJcmV0dXJuICFvcGVyYXRvcj09KHJlZik7Cgl9CgoJdmVjMmQgb3BlcmF0b3ItKGNvbnN0IHZlYzJkJiByZWYpIGNvbnN0IHsKCQlyZXR1cm4geyB4IC0gcmVmLngsIHkgLSByZWYueSB9OwoJfQoJdmVjMmQgb3BlcmF0b3IrKGNvbnN0IHZlYzJkJiByZWYpIGNvbnN0IHsKCQlyZXR1cm4geyB4ICsgcmVmLngsIHkgKyByZWYueSB9OwoJfQoKCWludCBkb3QoY29uc3QgdmVjMmQmIHJlZikgY29uc3QgewoJCXJldHVybiB4ICogcmVmLnkgKyB5ICogcmVmLng7Cgl9CgoJaW50IGNyb3NzKGNvbnN0IHZlYzJkJiByZWYpIGNvbnN0IHsKCQlyZXR1cm4geCAqIHJlZi55IC0gcmVmLnggKiB5OwoJfQp9OwoKdXNpbmcgVmVydGljZXMgPSBzdGQ6OnZlY3Rvcjx2ZWMyZD47CgphdXRvIGdldFZlcnRpY2VzKCkKewoJYXV0byBpID0gc3RkOjpiZWdpbih2KTsKCWF1dG8gZSA9IGk7IHN0ZDo6YWR2YW5jZShlLCBzdGQ6OnNpemUodikgLSBzdGQ6OnNpemUodikgJSAyKTsKCVZlcnRpY2VzIHJlc3VsdDsKCXdoaWxlIChpICE9IGUpIHsKCQlyZXN1bHQucHVzaF9iYWNrKHsgKmksICpzdGQ6Om5leHQoaSkgfSk7CgkJc3RkOjphZHZhbmNlKGksIDIpOwoJfQoJcmV0dXJuIHJlc3VsdDsKfQoKaW50IGZpbmRTdGFydFBvaW50KGNvbnN0IFZlcnRpY2VzJiB2ZXJ0aWNlcykKewoJYXV0byBwID0gMDsKCWF1dG8geCA9IHZlcnRpY2VzW3BdLngsIHkgPSB2ZXJ0aWNlc1twXS55OwoJZm9yIChzaXplX3QgaSA9IDA7IGkgPCBzdGQ6OnNpemUodmVydGljZXMpOyBpKyspIHsKCQlhdXRvIGRpZmYgPSB5IC0gdmVydGljZXNbaV0ueTsKCQlpZiAoZGlmZiA+IDApIHsKCQkJeSA9IHZlcnRpY2VzW2ldLnk7CgkJCXggPSB2ZXJ0aWNlc1tpXS54OwoJCQlwID0gaTsKCQl9CgkJZWxzZSBpZiAoZGlmZiA9PSAwICYmIHggPiB2ZXJ0aWNlc1tpXS54KSB7CgkJCXggPSB2ZXJ0aWNlc1tpXS54OwoJCQlwID0gaTsKCQl9Cgl9CglyZXR1cm4gcDsKfQoKYXV0byBnZXRDb252ZXhIdWxsKGNvbnN0IFZlcnRpY2VzJiB2ZXJ0aWNlcykKewoJVmVydGljZXMgcmVzdWx0OwoJaWYgKHN0ZDo6c2l6ZSh2ZXJ0aWNlcykgPT0gMCkgewoJCXJldHVybiByZXN1bHQ7Cgl9CglhdXRvIGEgPSBmaW5kU3RhcnRQb2ludCh2ZXJ0aWNlcyk7Cglmb3IgKDs7KSB7CgkJcmVzdWx0LnB1c2hfYmFjayh2ZXJ0aWNlc1thXSk7CgkJYXV0byBiID0gMDsKCQlmb3IgKHNpemVfdCBpID0gMTsgaSA8IHN0ZDo6c2l6ZSh2ZXJ0aWNlcyk7IGkrKykgewoJCQlhdXRvIGMgPSBpOwoJCQlpZiAodmVydGljZXNbYl0gPT0gdmVydGljZXNbYV0pIHsKCQkJCWIgPSBjOwoJCQl9CgkJCWVsc2UgewoJCQkJdmVjMmQgQSA9IHZlcnRpY2VzW2FdOwoJCQkJdmVjMmQgQiA9IHZlcnRpY2VzW2JdOwoJCQkJdmVjMmQgQyA9IHZlcnRpY2VzW2NdOwoJCQkJaW50IHYgPSAoQiAtIEEpLmNyb3NzKEMgLSBBKTsKCQkJCWlmICh2ID4gMCkgewoJCQkJCWIgPSBjOwoJCQkJfQoJCQl9CgkJfQoJCWEgPSBiOwoJCWlmIChyZXN1bHRbMF0gPT0gdmVydGljZXNbYV0pIHsKCQkJYnJlYWs7CgkJfQoJfQoKCXJldHVybiByZXN1bHQ7Cn0KCmF1dG8gZ2V0SW5jbHVzaW9uQ2lyY2xlKGNvbnN0IFZlcnRpY2VzJiB2ZXJ0aWNlcykKewoJVmVydGljZXMgcmVzdWx0OwoKCXJldHVybiByZXN1bHQ7Cn0KCi8vIOOCsOODreODvOODkOODq+WkieaVsDoKSElOU1RBTkNFIGhJbnN0OyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g54++5Zyo44Gu44Kk44Oz44K/44O844OV44Kn44Kk44K5CldDSEFSIHN6VGl0bGVbXT1fVCgiQ29udmV4U3F1YXJlIik7ICAgICAgICAgICAgICAgICAgLy8g44K/44Kk44OI44OrIOODkOODvOOBruODhuOCreOCueODiApXQ0hBUiBzeldpbmRvd0NsYXNzW109X1QoIkNPTlZFWFNRVUFSRSIpOyAgICAgICAgICAgIC8vIOODoeOCpOODsyDjgqbjgqPjg7Pjg4njgqYg44Kv44Op44K55ZCNCgovLyDjgZPjga7jgrPjg7zjg4kg44Oi44K444Ol44O844Or44Gr5ZCr44G+44KM44KL6Zai5pWw44Gu5a6j6KiA44KS6Lui6YCB44GX44G+44GZOgpBVE9NICAgICAgICAgICAgICAgIE15UmVnaXN0ZXJDbGFzcyhISU5TVEFOQ0UgaEluc3RhbmNlKTsKQk9PTCAgICAgICAgICAgICAgICBJbml0SW5zdGFuY2UoSElOU1RBTkNFLCBpbnQpOwpMUkVTVUxUIENBTExCQUNLICAgIFduZFByb2MoSFdORCwgVUlOVCwgV1BBUkFNLCBMUEFSQU0pOwpJTlRfUFRSIENBTExCQUNLICAgIEFib3V0KEhXTkQsIFVJTlQsIFdQQVJBTSwgTFBBUkFNKTsKCmludCBBUElFTlRSWSB3V2luTWFpbihfSW5fIEhJTlNUQU5DRSBoSW5zdGFuY2UsCiAgICAgICAgICAgICAgICAgICAgIF9Jbl9vcHRfIEhJTlNUQU5DRSBoUHJldkluc3RhbmNlLAogICAgICAgICAgICAgICAgICAgICBfSW5fIExQV1NUUiAgICBscENtZExpbmUsCiAgICAgICAgICAgICAgICAgICAgIF9Jbl8gaW50ICAgICAgIG5DbWRTaG93KQp7CiAgICBVTlJFRkVSRU5DRURfUEFSQU1FVEVSKGhQcmV2SW5zdGFuY2UpOwogICAgVU5SRUZFUkVOQ0VEX1BBUkFNRVRFUihscENtZExpbmUpOwoKICAgIC8vIFRPRE86IOOBk+OBk+OBq+OCs+ODvOODieOCkuaMv+WFpeOBl+OBpuOBj+OBoOOBleOBhOOAggoJYXV0byB2ZXJ0aWNlcyA9IGdldFZlcnRpY2VzKCk7CglhdXRvIGNvbnZleF9odWxsID0gZ2V0Q29udmV4SHVsbCh2ZXJ0aWNlcyk7CgogICAgLy8g44Kw44Ot44O844OQ44Or5paH5a2X5YiX44KS5Yid5pyf5YyW44GZ44KLCiAgICBNeVJlZ2lzdGVyQ2xhc3MoaEluc3RhbmNlKTsKCiAgICAvLyDjgqLjg5fjg6rjgrHjg7zjgrfjg6fjg7PliJ3mnJ/ljJbjga7lrp/ooYw6CiAgICBpZiAoIUluaXRJbnN0YW5jZSAoaEluc3RhbmNlLCBuQ21kU2hvdykpCiAgICB7CiAgICAgICAgcmV0dXJuIEZBTFNFOwogICAgfQoKICAgIE1TRyBtc2c7CgogICAgLy8g44Oh44Kk44OzIOODoeODg+OCu+ODvOOCuCDjg6vjg7zjg5c6CiAgICB3aGlsZSAoR2V0TWVzc2FnZSgmbXNnLCBudWxscHRyLCAwLCAwKSkKICAgIHsKICAgICAgICBUcmFuc2xhdGVNZXNzYWdlKCZtc2cpOwogICAgICAgIERpc3BhdGNoTWVzc2FnZSgmbXNnKTsKICAgIH0KCiAgICByZXR1cm4gKGludCkgbXNnLndQYXJhbTsKfQoKCgovLwovLyAg6Zai5pWwOiBNeVJlZ2lzdGVyQ2xhc3MoKQovLwovLyAg55uu55qEOiDjgqbjgqPjg7Pjg4njgqYg44Kv44Op44K544KS55m76Yyy44GX44G+44GZ44CCCi8vCkFUT00gTXlSZWdpc3RlckNsYXNzKEhJTlNUQU5DRSBoSW5zdGFuY2UpCnsKICAgIFdORENMQVNTRVhXIHdjZXg7CgogICAgd2NleC5jYlNpemUgPSBzaXplb2YoV05EQ0xBU1NFWCk7CgogICAgd2NleC5zdHlsZSAgICAgICAgICA9IENTX0hSRURSQVcgfCBDU19WUkVEUkFXOwogICAgd2NleC5scGZuV25kUHJvYyAgICA9IFduZFByb2M7CiAgICB3Y2V4LmNiQ2xzRXh0cmEgICAgID0gMDsKICAgIHdjZXguY2JXbmRFeHRyYSAgICAgPSAwOwogICAgd2NleC5oSW5zdGFuY2UgICAgICA9IGhJbnN0YW5jZTsKICAgIHdjZXguaEljb24gICAgICAgICAgPSBMb2FkSWNvbihudWxscHRyLCBJRElfQVBQTElDQVRJT04pOwogICAgd2NleC5oQ3Vyc29yICAgICAgICA9IExvYWRDdXJzb3IobnVsbHB0ciwgSURDX0FSUk9XKTsKICAgIHdjZXguaGJyQmFja2dyb3VuZCAgPSAoSEJSVVNIKShDT0xPUl9XSU5ET1crMSk7CiAgICB3Y2V4Lmxwc3pNZW51TmFtZSAgID0gTlVMTDsKICAgIHdjZXgubHBzekNsYXNzTmFtZSAgPSBzeldpbmRvd0NsYXNzOwogICAgd2NleC5oSWNvblNtICAgICAgICA9IExvYWRJY29uKG51bGxwdHIsIElESV9BUFBMSUNBVElPTik7CgogICAgcmV0dXJuIFJlZ2lzdGVyQ2xhc3NFeFcoJndjZXgpOwp9CgovLwovLyAgIOmWouaVsDogSW5pdEluc3RhbmNlKEhJTlNUQU5DRSwgaW50KQovLwovLyAgIOebrueahDog44Kk44Oz44K544K/44Oz44K5IOODj+ODs+ODieODq+OCkuS/neWtmOOBl+OBpuOAgeODoeOCpOODsyDjgqbjgqPjg7Pjg4njgqbjgpLkvZzmiJDjgZfjgb7jgZkKLy8KLy8gICDjgrPjg6Hjg7Pjg4g6Ci8vCi8vICAgICAgICDjgZPjga7plqLmlbDjgafjgIHjgrDjg63jg7zjg5Djg6vlpInmlbDjgafjgqTjg7Pjgrnjgr/jg7Pjgrkg44OP44Oz44OJ44Or44KS5L+d5a2Y44GX44CBCi8vICAgICAgICDjg6HjgqTjg7Mg44OX44Ot44Kw44Op44OgIOOCpuOCo+ODs+ODieOCpuOCkuS9nOaIkOOBiuOCiOOBs+ihqOekuuOBl+OBvuOBmeOAggovLwpCT09MIEluaXRJbnN0YW5jZShISU5TVEFOQ0UgaEluc3RhbmNlLCBpbnQgbkNtZFNob3cpCnsKICAgaEluc3QgPSBoSW5zdGFuY2U7IC8vIOOCsOODreODvOODkOODq+WkieaVsOOBq+OCpOODs+OCueOCv+ODs+OCuSDjg4/jg7Pjg4njg6vjgpLmoLzntI3jgZnjgosKCiAgIEhXTkQgaFduZCA9IENyZWF0ZVdpbmRvd1coc3pXaW5kb3dDbGFzcywgc3pUaXRsZSwgV1NfT1ZFUkxBUFBFRFdJTkRPVywKICAgICAgQ1dfVVNFREVGQVVMVCwgMCwgQ1dfVVNFREVGQVVMVCwgMCwgbnVsbHB0ciwgbnVsbHB0ciwgaEluc3RhbmNlLCBudWxscHRyKTsKCiAgIGlmICghaFduZCkKICAgewogICAgICByZXR1cm4gRkFMU0U7CiAgIH0KCiAgIFNob3dXaW5kb3coaFduZCwgbkNtZFNob3cpOwogICBVcGRhdGVXaW5kb3coaFduZCk7CgogICByZXR1cm4gVFJVRTsKfQoKLy8KLy8gIOmWouaVsDogV25kUHJvYyhIV05ELCBVSU5ULCBXUEFSQU0sIExQQVJBTSkKLy8KLy8gIOebrueahDog44Oh44Kk44OzIOOCpuOCo+ODs+ODieOCpuOBruODoeODg+OCu+ODvOOCuOOCkuWHpueQhuOBl+OBvuOBmeOAggovLwovLyAgV01fQ09NTUFORCAgLSDjgqLjg5fjg6rjgrHjg7zjgrfjg6fjg7Mg44Oh44OL44Ol44O844Gu5Yem55CGCi8vICBXTV9QQUlOVCAgICAtIOODoeOCpOODsyDjgqbjgqPjg7Pjg4njgqbjgpLmj4/nlLvjgZnjgosKLy8gIFdNX0RFU1RST1kgIC0g5Lit5q2i44Oh44OD44K744O844K444KS6KGo56S644GX44Gm5oi744KLCi8vCi8vCkxSRVNVTFQgQ0FMTEJBQ0sgV25kUHJvYyhIV05EIGhXbmQsIFVJTlQgbWVzc2FnZSwgV1BBUkFNIHdQYXJhbSwgTFBBUkFNIGxQYXJhbSkKewogICAgc3dpdGNoIChtZXNzYWdlKQogICAgewoJY2FzZSBXTV9MQlVUVE9ORE9XTjoKCQl7CgkJCWludCB4ID0gTE9XT1JEKGxQYXJhbSk7CgkJCWludCB5ID0gSElXT1JEKGxQYXJhbSk7CgkJCXYucHVzaF9iYWNrKHsgeCB9KTsKCQkJdi5wdXNoX2JhY2soeyB5IH0pOwoJCQk6OkludmFsaWRhdGVSZWN0KGhXbmQsIG51bGxwdHIsIHRydWUpOwoJCX0KCQlicmVhazsKCWNhc2UgV01fUkJVVFRPTkRPV046CgkJewoJCQl2LmNsZWFyKCk7CgkJCTo6SW52YWxpZGF0ZVJlY3QoaFduZCwgbnVsbHB0ciwgdHJ1ZSk7CgkJfQoJCWJyZWFrOwoJY2FzZSBXTV9NQlVUVE9ORE9XTjoKCQl7CgkJCXN0ZDo6dmVjdG9yPGludD4gdG1weyAxMzYsIDU3NywgMTEwLCA5MjcsIDQ3MiwgMTk5LCAxNTcsIDgwOCwgMzg4LCA1OTgsIDk0LCAzMSwgMzg4LCAxNTcsIDMyNSwgNDA5LCA3ODcsIDg5NywgODUwLCA1OTggfTsKCQkJdi5zd2FwKHRtcCk7CgkJCTo6SW52YWxpZGF0ZVJlY3QoaFduZCwgbnVsbHB0ciwgdHJ1ZSk7CgkJfQoJCWJyZWFrOwoJY2FzZSBXTV9QQUlOVDoKICAgICAgICB7CiAgICAgICAgICAgIFBBSU5UU1RSVUNUIHBzOwogICAgICAgICAgICBIREMgaGRjID0gQmVnaW5QYWludChoV25kLCAmcHMpOwogICAgICAgICAgICAvLyBUT0RPOiBIREMg44KS5L2/55So44GZ44KL5o+P55S744Kz44O844OJ44KS44GT44GT44Gr6L+95Yqg44GX44Gm44GP44Gg44GV44GELi4uCgoJCQk6OlJlY3RhbmdsZShoZGMsIDAsIDAsIDk5OSwgOTk5KTsKCgkJCXsKCQkJCVZlcnRpY2VzIHZlcnRpY2VzID0gZ2V0VmVydGljZXMoKTsKCQkJCWZvciAoYXV0byYgdiA6IHZlcnRpY2VzKSB7CgkJCQkJOjpSZWN0YW5nbGUoaGRjLCB2LnggLSAxLCB2LnkgLSAxLCB2LnggKyAxLCB2LnkgKyAxKTsKCQkJCX0KCQkJfQoKCQkJewoJCQkJVmVydGljZXMgdmVydGljZXMgPSBnZXRDb252ZXhIdWxsKGdldFZlcnRpY2VzKCkpOwoJCQkJaWYgKHN0ZDo6c2l6ZSh2ZXJ0aWNlcykgPiAwKSB7CgkJCQkJewoJCQkJCQlmb3IgKHNpemVfdCBpID0gMDsgaSA8IHN0ZDo6c2l6ZSh2ZXJ0aWNlcyk7IGkrKykgewoJCQkJCQkJY2hhciB0eHRbMjU1XTsKCQkJCQkJCXNwcmludGZfcyh0eHQsIDI1NSwgIiV6dSIsIGkpOwoJCQkJCQkJOjpUZXh0T3V0QShoZGMsIHZlcnRpY2VzW2ldLngsIHZlcnRpY2VzW2ldLnksIHR4dCwgc3RybGVuKHR4dCkpOwoJCQkJCQl9CgkJCQkJfQoKCQkJCQl7CgkJCQkJCUhCUlVTSCByZWQgPSA6OkNyZWF0ZVNvbGlkQnJ1c2goUkdCKDI1NSwgMCwgMCkpOwoJCQkJCQlIR0RJT0JKIGJydXNoID0gOjpTZWxlY3RPYmplY3QoaGRjLCByZWQpOwoJCQkJCQlIR0RJT0JKIHBlbiA9IDo6U2VsZWN0T2JqZWN0KGhkYywgOjpHZXRTdG9ja09iamVjdChOVUxMX1BFTikpOwoJCQkJCQlmb3IgKGF1dG8mIHYgOiB2ZXJ0aWNlcykgewoJCQkJCQkJOjpSZWN0YW5nbGUoaGRjLCB2LnggLSAyLCB2LnkgLSAyLCB2LnggKyAyLCB2LnkgKyAyKTsKCQkJCQkJfQoJCQkJCQk6OlNlbGVjdE9iamVjdChoZGMsIHBlbik7CgkJCQkJCTo6U2VsZWN0T2JqZWN0KGhkYywgYnJ1c2gpOwoJCQkJCQk6OkRlbGV0ZU9iamVjdChyZWQpOwoJCQkJCX0KCQkJCQl7CgkJCQkJCWF1dG8gaSA9IHN0ZDo6YmVnaW4odmVydGljZXMpOwoJCQkJCQlhdXRvIGUgPSBzdGQ6OmVuZCh2ZXJ0aWNlcyk7CgkJCQkJCTo6TW92ZVRvRXgoaGRjLCBpLT54LCBpLT55LCBudWxscHRyKTsKCQkJCQkJd2hpbGUgKGkgIT0gZSkgewoJCQkJCQkJYXV0byB0byA9IHN0ZDo6bmV4dChpKTsKCQkJCQkJCWlmICh0byA9PSBlKQoJCQkJCQkJCXRvID0gc3RkOjpiZWdpbih2ZXJ0aWNlcyk7CgkJCQkJCQk6OkxpbmVUbyhoZGMsIHRvLT54LCB0by0+eSk7CgkJCQkJCQlpKys7CgkJCQkJCX0KCQkJCQl9CgkJCQl9CgkJCX0KCiAgICAgICAgICAgIEVuZFBhaW50KGhXbmQsICZwcyk7CiAgICAgICAgfQogICAgICAgIGJyZWFrOwogICAgY2FzZSBXTV9ERVNUUk9ZOgogICAgICAgIFBvc3RRdWl0TWVzc2FnZSgwKTsKICAgICAgICBicmVhazsKICAgIGRlZmF1bHQ6CiAgICAgICAgcmV0dXJuIERlZldpbmRvd1Byb2MoaFduZCwgbWVzc2FnZSwgd1BhcmFtLCBsUGFyYW0pOwogICAgfQogICAgcmV0dXJuIDA7Cn0KCg==