diff --git a/src/libs/solutions/terminal/surfaceintegration.h b/src/libs/solutions/terminal/surfaceintegration.h index 5959e2b53a7..99b9538de15 100644 --- a/src/libs/solutions/terminal/surfaceintegration.h +++ b/src/libs/solutions/terminal/surfaceintegration.h @@ -14,6 +14,9 @@ public: virtual void onBell() {} virtual void onTitle(const QString &title) { Q_UNUSED(title); } + + virtual void onSetClipboard(const QByteArray &text) { Q_UNUSED(text); } + virtual void onGetClipboard() {} }; } // namespace TerminalSolution diff --git a/src/libs/solutions/terminal/terminalsurface.cpp b/src/libs/solutions/terminal/terminalsurface.cpp index 3f816670c34..8baf743e2f0 100644 --- a/src/libs/solutions/terminal/terminalsurface.cpp +++ b/src/libs/solutions/terminal/terminalsurface.cpp @@ -142,6 +142,41 @@ struct TerminalSurfacePrivate VTermState *vts = vterm_obtain_state(m_vterm.get()); vterm_state_set_unrecognised_fallbacks(vts, &m_vtermStateFallbacks, this); + + memset(&m_vtermSelectionCallbacks, 0, sizeof(m_vtermSelectionCallbacks)); + + m_vtermSelectionCallbacks.query = [](VTermSelectionMask mask, void *user) { + if (!(mask & 0xF)) + return 0; + + auto p = static_cast(user); + if (p->m_surfaceIntegration) + p->m_surfaceIntegration->onGetClipboard(); + + return 0; + }; + + m_vtermSelectionCallbacks.set = + [](VTermSelectionMask mask, VTermStringFragment frag, void *user) { + if (!(mask & 0xF)) + return 0; + + auto p = static_cast(user); + if (frag.initial) + p->m_selectionBuffer.clear(); + + p->m_selectionBuffer.append(frag.str, frag.len); + if (!frag.final) + return 1; + + if (p->m_surfaceIntegration) + p->m_surfaceIntegration->onSetClipboard(p->m_selectionBuffer); + + return 1; + }; + + vterm_state_set_selection_callbacks(vts, &m_vtermSelectionCallbacks, this, nullptr, 256); + vterm_state_set_bold_highbright(vts, true); VTermColor fg; @@ -363,6 +398,8 @@ struct TerminalSurfacePrivate VTermScreenCallbacks m_vtermScreenCallbacks; VTermStateFallbacks m_vtermStateFallbacks; + VTermSelectionCallbacks m_vtermSelectionCallbacks; + Cursor m_cursor; QString m_currentCommand; @@ -375,6 +412,7 @@ struct TerminalSurfacePrivate TerminalSurface *q; QTimer m_delayWriteTimer; QByteArray m_writeBuffer; + QByteArray m_selectionBuffer; TerminalSurface::WriteToPty m_writeToPty; }; diff --git a/src/plugins/terminal/shellintegration.cpp b/src/plugins/terminal/shellintegration.cpp index 44cee54b978..c0cad7f3dd2 100644 --- a/src/plugins/terminal/shellintegration.cpp +++ b/src/plugins/terminal/shellintegration.cpp @@ -179,4 +179,9 @@ void ShellIntegration::prepareProcess(Utils::Process &process) process.setEnvironment(env); } +void ShellIntegration::onSetClipboard(const QByteArray &text) +{ + setClipboardAndSelection(QString::fromLocal8Bit(text)); +} + } // namespace Terminal diff --git a/src/plugins/terminal/shellintegration.h b/src/plugins/terminal/shellintegration.h index aac63e63e84..22cf4e79a34 100644 --- a/src/plugins/terminal/shellintegration.h +++ b/src/plugins/terminal/shellintegration.h @@ -23,6 +23,8 @@ public: void onBell() override; void onTitle(const QString &title) override; + void onSetClipboard(const QByteArray &text) override; + void prepareProcess(Utils::Process &process); signals: diff --git a/src/plugins/terminal/tests/copy b/src/plugins/terminal/tests/copy new file mode 100755 index 00000000000..fdd9e71d187 --- /dev/null +++ b/src/plugins/terminal/tests/copy @@ -0,0 +1,45 @@ +#!/bin/bash + +function set_clipboard() { + b=$(echo -ne "$2" | base64); + printf "\033]52;$1;$b\a\n" +} + +function test_clipboard() { + echo -e "\033[1m ⎆ The Clipboard should now contain '$2'\033[0m" + + set_clipboard "$1" "$2" + + read -p " ⎆ Press enter to continue " -n1 -s + echo + echo +} + +test_clipboard "c" "copypasta!" +test_clipboard "p" "Mask: p" +test_clipboard "q" "Mask: q" +test_clipboard "s" "Mask: s" +test_clipboard "cpqs" "Mask: cpqs" + +echo -e "\033[1m ⎆ The Clipboard should now be empty\033[0m" +printf "\033]52;cpqs;\a\n" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +echo -e "\033[1m ⎆ The Clipboard should still be empty\033[0m" +set_clipboard "01234567" "Hello World!" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo + +test_clipboard "c01234567" "Hello World!" + +echo -e "\033[1m ⎆ The Clipboard should now contain the source of terminalsurface.cpp\033[0m" +printf "\033]52;c;Ly8gQ29weXJpZ2h0IChDKSAyMDIyIFRoZSBRdCBDb21wYW55IEx0ZC4KLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IExpY2Vuc2VSZWYtUXQtQ29tbWVyY2lhbCBPUiBHUEwtMy4wKyBPUiBHUEwtMy4wIFdJVEggUXQtR1BMLWV4Y2VwdGlvbi0xLjAKCiNpbmNsdWRlICJ0ZXJtaW5hbHN1cmZhY2UuaCIKI2luY2x1ZGUgInN1cmZhY2VpbnRlZ3JhdGlvbi5oIgoKI2luY2x1ZGUgImtleXMuaCIKI2luY2x1ZGUgInNjcm9sbGJhY2suaCIKCiNpbmNsdWRlIDx2dGVybS5oPgoKI2luY2x1ZGUgPFFMb2dnaW5nQ2F0ZWdvcnk+CiNpbmNsdWRlIDxRVGltZXI+CgpuYW1lc3BhY2UgVGVybWluYWxTb2x1dGlvbiB7CgpRX0xPR0dJTkdfQ0FURUdPUlkobG9nLCAicXRjLnRlcm1pbmFsLnN1cmZhY2UiLCBRdFdhcm5pbmdNc2cpOwoKUUNvbG9yIHRvUUNvbG9yKGNvbnN0IFZUZXJtQ29sb3IgJmMpCnsKICAgIHJldHVybiBRQ29sb3IocVJnYihjLnJnYi5yZWQsIGMucmdiLmdyZWVuLCBjLnJnYi5ibHVlKSk7Cn07Cgpjb25zdGV4cHIgaW50IGJhdGNoRmx1c2hTaXplID0gMjU2OwoKc3RydWN0IFRlcm1pbmFsU3VyZmFjZVByaXZhdGUKewogICAgVGVybWluYWxTdXJmYWNlUHJpdmF0ZShUZXJtaW5hbFN1cmZhY2UgKnN1cmZhY2UsIGNvbnN0IFFTaXplICZpbml0aWFsR3JpZFNpemUpCiAgICAgICAgOiBtX3Z0ZXJtKHZ0ZXJtX25ldyhpbml0aWFsR3JpZFNpemUuaGVpZ2h0KCksIGluaXRpYWxHcmlkU2l6ZS53aWR0aCgpKSwgdnRlcm1fZnJlZSkKICAgICAgICAsIG1fdnRlcm1TY3JlZW4odnRlcm1fb2J0YWluX3NjcmVlbihtX3Z0ZXJtLmdldCgpKSkKICAgICAgICAsIG1fc2Nyb2xsYmFjayhzdGQ6Om1ha2VfdW5pcXVlPFNjcm9sbGJhY2s+KDUwMDApKQogICAgICAgICwgcShzdXJmYWNlKQogICAge30KCiAgICB2b2lkIGZsdXNoKCkKICAgIHsKICAgICAgICBpZiAobV93cml0ZUJ1ZmZlci5pc0VtcHR5KCkpCiAgICAgICAgICAgIHJldHVybjsKCiAgICAgICAgUUJ5dGVBcnJheSBkYXRhID0gbV93cml0ZUJ1ZmZlci5sZWZ0KGJhdGNoRmx1c2hTaXplKTsKICAgICAgICBxaW50NjQgcmVzdWx0ID0gbV93cml0ZVRvUHR5KGRhdGEpOwoKICAgICAgICBpZiAocmVzdWx0ICE9IGRhdGEuc2l6ZSgpKSB7CiAgICAgICAgICAgIC8vIE5vdCBhbGwgZGF0YSB3YXMgd3JpdHRlbiwgcmVtb3ZlIHRoZSB1bndyaXR0ZW4gZGF0YSBmcm9tIHRoZSBhcnJheQogICAgICAgICAgICBkYXRhLnJlc2l6ZShxTWF4KDAsIHJlc3VsdCkpOwogICAgICAgIH0KCiAgICAgICAgLy8gUmVtb3ZlIHRoZSB3cml0dGVuIGRhdGEgZnJvbSB0aGUgYnVmZmVyCiAgICAgICAgaWYgKGRhdGEuc2l6ZSgpID4gMCkKICAgICAgICAgICAgbV93cml0ZUJ1ZmZlciA9IG1fd3JpdGVCdWZmZXIubWlkKGRhdGEuc2l6ZSgpKTsKCiAgICAgICAgaWYgKCFtX3dyaXRlQnVmZmVyLmlzRW1wdHkoKSkKICAgICAgICAgICAgbV9kZWxheVdyaXRlVGltZXIuc3RhcnQoKTsKICAgIH0KCiAgICB2b2lkIGluaXQoKQogICAgewogICAgICAgIG1fZGVsYXlXcml0ZVRpbWVyLnNldEludGVydmFsKDEpOwogICAgICAgIG1fZGVsYXlXcml0ZVRpbWVyLnNldFNpbmdsZVNob3QodHJ1ZSk7CgogICAgICAgIFFPYmplY3Q6OmNvbm5lY3QoJm1fZGVsYXlXcml0ZVRpbWVyLCAmUVRpbWVyOjp0aW1lb3V0LCAmbV9kZWxheVdyaXRlVGltZXIsIFt0aGlzXSB7CiAgICAgICAgICAgIGZsdXNoKCk7CiAgICAgICAgfSk7CgogICAgICAgIHZ0ZXJtX3NldF91dGY4KG1fdnRlcm0uZ2V0KCksIHRydWUpOwoKICAgICAgICBzdGF0aWMgYXV0byB3cml0ZVRvUHR5ID0gW10oY29uc3QgY2hhciAqcywgc2l6ZV90IGxlbiwgdm9pZCAqdXNlcikgewogICAgICAgICAgICBhdXRvIHAgPSBzdGF0aWNfY2FzdDxUZXJtaW5hbFN1cmZhY2VQcml2YXRlICo+KHVzZXIpOwogICAgICAgICAgICBRQnl0ZUFycmF5IGQocywgbGVuKTsKCiAgICAgICAgICAgIC8vIElmIGl0cyBqdXN0IGEgY291cGxlIG9mIGNoYXJzLCBvciB3ZSBhbHJlYWR5IGhhdmUgZGF0YSBpbiB0aGUgd3JpdGVCdWZmZXIsCiAgICAgICAgICAgIC8vIGFkZCB0aGUgbmV3IGRhdGEgdG8gdGhlIHdyaXRlIGJ1ZmZlciBhbmQgc3RhcnQgdGhlIGRlbGF5IHRpbWVyCiAgICAgICAgICAgIGlmIChkLnNpemUoKSA8IGJhdGNoRmx1c2hTaXplIHx8ICFwLT5tX3dyaXRlQnVmZmVyLmlzRW1wdHkoKSkgewogICAgICAgICAgICAgICAgcC0+bV93cml0ZUJ1ZmZlci5hcHBlbmQoZCk7CiAgICAgICAgICAgICAgICBwLT5tX2RlbGF5V3JpdGVUaW1lci5zdGFydCgpOwogICAgICAgICAgICAgICAgcmV0dXJuOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBUcnkgdG8gd3JpdGUgdGhlIGRhdGEgLi4uCiAgICAgICAgICAgIHFpbnQ2NCByZXN1bHQgPSBwLT5tX3dyaXRlVG9QdHkoZCk7CgogICAgICAgICAgICBpZiAocmVzdWx0ICE9IGQuc2l6ZSgpKSB7CiAgICAgICAgICAgICAgICAvLyBpZiB3cml0aW5nIGZhaWxlZCwgYXBwZW5kIHRoZSBkYXRhIHRvIHRoZSB3cml0ZUJ1ZmZlciBhbmQgc3RhcnQgdGhlIGRlbGF5IHRpbWVyCgogICAgICAgICAgICAgICAgLy8gQ2hlY2sgaWYgcGFydGlhbCBkYXRhIG1heSBoYXZlIGFscmVhZHkgYmVlbiB3cml0dGVuIC4uLgogICAgICAgICAgICAgICAgaWYgKHJlc3VsdCA8PSAwKQogICAgICAgICAgICAgICAgICAgIHAtPm1fd3JpdGVCdWZmZXIuYXBwZW5kKGQpOwogICAgICAgICAgICAgICAgZWxzZQogICAgICAgICAgICAgICAgICAgIHAtPm1fd3JpdGVCdWZmZXIuYXBwZW5kKGQubWlkKHJlc3VsdCkpOwoKICAgICAgICAgICAgICAgIHAtPm1fZGVsYXlXcml0ZVRpbWVyLnN0YXJ0KCk7CiAgICAgICAgICAgIH0KICAgICAgICB9OwoKICAgICAgICB2dGVybV9vdXRwdXRfc2V0X2NhbGxiYWNrKG1fdnRlcm0uZ2V0KCksIHdyaXRlVG9QdHksIHRoaXMpOwoKICAgICAgICBtZW1zZXQoJm1fdnRlcm1TY3JlZW5DYWxsYmFja3MsIDAsIHNpemVvZihtX3Z0ZXJtU2NyZWVuQ2FsbGJhY2tzKSk7CgogICAgICAgIG1fdnRlcm1TY3JlZW5DYWxsYmFja3MuZGFtYWdlID0gW10oVlRlcm1SZWN0IHJlY3QsIHZvaWQgKnVzZXIpIHsKICAgICAgICAgICAgYXV0byBwID0gc3RhdGljX2Nhc3Q8VGVybWluYWxTdXJmYWNlUHJpdmF0ZSAqPih1c2VyKTsKICAgICAgICAgICAgcC0+aW52YWxpZGF0ZShyZWN0KTsKICAgICAgICAgICAgcmV0dXJuIDE7CiAgICAgICAgfTsKICAgICAgICBtX3Z0ZXJtU2NyZWVuQ2FsbGJhY2tzLnNiX3B1c2hsaW5lID0gW10oaW50IGNvbHMsIGNvbnN0IFZUZXJtU2NyZWVuQ2VsbCAqY2VsbHMsIHZvaWQgKnVzZXIpIHsKICAgICAgICAgICAgYXV0byBwID0gc3RhdGljX2Nhc3Q8VGVybWluYWxTdXJmYWNlUHJpdmF0ZSAqPih1c2VyKTsKICAgICAgICAgICAgcmV0dXJuIHAtPnNiX3B1c2hsaW5lKGNvbHMsIGNlbGxzKTsKICAgICAgICB9OwogICAgICAgIG1fdnRlcm1TY3JlZW5DYWxsYmFja3Muc2JfcG9wbGluZSA9IFtdKGludCBjb2xzLCBWVGVybVNjcmVlbkNlbGwgKmNlbGxzLCB2b2lkICp1c2VyKSB7CiAgICAgICAgICAgIGF1dG8gcCA9IHN0YXRpY19jYXN0PFRlcm1pbmFsU3VyZmFjZVByaXZhdGUgKj4odXNlcik7CiAgICAgICAgICAgIHJldHVybiBwLT5zYl9wb3BsaW5lKGNvbHMsIGNlbGxzKTsKICAgICAgICB9OwogICAgICAgIG1fdnRlcm1TY3JlZW5DYWxsYmFja3Muc2V0dGVybXByb3AgPSBbXShWVGVybVByb3AgcHJvcCwgVlRlcm1WYWx1ZSAqdmFsLCB2b2lkICp1c2VyKSB7CiAgICAgICAgICAgIGF1dG8gcCA9IHN0YXRpY19jYXN0PFRlcm1pbmFsU3VyZmFjZVByaXZhdGUgKj4odXNlcik7CiAgICAgICAgICAgIHJldHVybiBwLT5zZXRUZXJtaW5hbFByb3BlcnRpZXMocHJvcCwgdmFsKTsKICAgICAgICB9OwogICAgICAgIG1fdnRlcm1TY3JlZW5DYWxsYmFja3MubW92ZWN1cnNvciA9CiAgICAgICAgICAgIFtdKFZUZXJtUG9zIHBvcywgVlRlcm1Qb3Mgb2xkcG9zLCBpbnQgdmlzaWJsZSwgdm9pZCAqdXNlcikgewogICAgICAgICAgICAgICAgYXV0byBwID0gc3RhdGljX2Nhc3Q8VGVybWluYWxTdXJmYWNlUHJpdmF0ZSAqPih1c2VyKTsKICAgICAgICAgICAgICAgIHJldHVybiBwLT5tb3ZlY3Vyc29yKHBvcywgb2xkcG9zLCB2aXNpYmxlKTsKICAgICAgICAgICAgfTsKICAgICAgICBtX3Z0ZXJtU2NyZWVuQ2FsbGJhY2tzLnNiX2NsZWFyID0gW10odm9pZCAqdXNlcikgewogICAgICAgICAgICBhdXRvIHAgPSBzdGF0aWNfY2FzdDxUZXJtaW5hbFN1cmZhY2VQcml2YXRlICo+KHVzZXIpOwogICAgICAgICAgICByZXR1cm4gcC0+c2JfY2xlYXIoKTsKICAgICAgICB9OwogICAgICAgIG1fdnRlcm1TY3JlZW5DYWxsYmFja3MuYmVsbCA9IFtdKHZvaWQgKnVzZXIpIHsKICAgICAgICAgICAgYXV0byBwID0gc3RhdGljX2Nhc3Q8VGVybWluYWxTdXJmYWNlUHJpdmF0ZSAqPih1c2VyKTsKICAgICAgICAgICAgaWYgKHAtPm1fc3VyZmFjZUludGVncmF0aW9uKQogICAgICAgICAgICAgICAgcC0+bV9zdXJmYWNlSW50ZWdyYXRpb24tPm9uQmVsbCgpOwogICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICB9OwoKICAgICAgICB2dGVybV9zY3JlZW5fc2V0X2NhbGxiYWNrcyhtX3Z0ZXJtU2NyZWVuLCAmbV92dGVybVNjcmVlbkNhbGxiYWNrcywgdGhpcyk7CiAgICAgICAgdnRlcm1fc2NyZWVuX3NldF9kYW1hZ2VfbWVyZ2UobV92dGVybVNjcmVlbiwgVlRFUk1fREFNQUdFX1NDUk9MTCk7CiAgICAgICAgdnRlcm1fc2NyZWVuX2VuYWJsZV9hbHRzY3JlZW4obV92dGVybVNjcmVlbiwgdHJ1ZSk7CgogICAgICAgIG1lbXNldCgmbV92dGVybVN0YXRlRmFsbGJhY2tzLCAwLCBzaXplb2YobV92dGVybVN0YXRlRmFsbGJhY2tzKSk7CgogICAgICAgIG1fdnRlcm1TdGF0ZUZhbGxiYWNrcy5vc2MgPSBbXShpbnQgY21kLCBWVGVybVN0cmluZ0ZyYWdtZW50IGZyYWdtZW50LCB2b2lkICp1c2VyKSB7CiAgICAgICAgICAgIGF1dG8gcCA9IHN0YXRpY19jYXN0PFRlcm1pbmFsU3VyZmFjZVByaXZhdGUgKj4odXNlcik7CiAgICAgICAgICAgIHJldHVybiBwLT5vc2MoY21kLCBmcmFnbWVudCk7CiAgICAgICAgfTsKCiAgICAgICAgVlRlcm1TdGF0ZSAqdnRzID0gdnRlcm1fb2J0YWluX3N0YXRlKG1fdnRlcm0uZ2V0KCkpOwogICAgICAgIHZ0ZXJtX3N0YXRlX3NldF91bnJlY29nbmlzZWRfZmFsbGJhY2tzKHZ0cywgJm1fdnRlcm1TdGF0ZUZhbGxiYWNrcywgdGhpcyk7CgogICAgICAgIG1lbXNldCgmbV92dGVybVNlbGVjdGlvbkNhbGxiYWNrcywgMCwgc2l6ZW9mKG1fdnRlcm1TZWxlY3Rpb25DYWxsYmFja3MpKTsKCiAgICAgICAgbV92dGVybVNlbGVjdGlvbkNhbGxiYWNrcy5xdWVyeSA9IFtdKFZUZXJtU2VsZWN0aW9uTWFzayBtYXNrLCB2b2lkICp1c2VyKSB7CiAgICAgICAgICAgIGlmICghKG1hc2sgJiAweEYpKQogICAgICAgICAgICAgICAgcmV0dXJuIDA7CgogICAgICAgICAgICBhdXRvIHAgPSBzdGF0aWNfY2FzdDxUZXJtaW5hbFN1cmZhY2VQcml2YXRlICo+KHVzZXIpOwogICAgICAgICAgICBpZiAocC0+bV9zdXJmYWNlSW50ZWdyYXRpb24pCiAgICAgICAgICAgICAgICBwLT5tX3N1cmZhY2VJbnRlZ3JhdGlvbi0+b25HZXRDbGlwYm9hcmQoKTsKCiAgICAgICAgICAgIHJldHVybiAwOwogICAgICAgIH07CgogICAgICAgIG1fdnRlcm1TZWxlY3Rpb25DYWxsYmFja3Muc2V0ID0KICAgICAgICAgICAgW10oVlRlcm1TZWxlY3Rpb25NYXNrIG1hc2ssIFZUZXJtU3RyaW5nRnJhZ21lbnQgZnJhZywgdm9pZCAqdXNlcikgewogICAgICAgICAgICAgICAgaWYgKCEobWFzayAmIDB4RikpCiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDA7CgogICAgICAgICAgICAgICAgYXV0byBwID0gc3RhdGljX2Nhc3Q8VGVybWluYWxTdXJmYWNlUHJpdmF0ZSAqPih1c2VyKTsKICAgICAgICAgICAgICAgIGlmIChmcmFnLmluaXRpYWwpCiAgICAgICAgICAgICAgICAgICAgcC0+bV9zZWxlY3Rpb25CdWZmZXIuY2xlYXIoKTsKCiAgICAgICAgICAgICAgICBwLT5tX3NlbGVjdGlvbkJ1ZmZlci5hcHBlbmQoZnJhZy5zdHIsIGZyYWcubGVuKTsKICAgICAgICAgICAgICAgIGlmICghZnJhZy5maW5hbCkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gMTsKCiAgICAgICAgICAgICAgICBpZiAocC0+bV9zdXJmYWNlSW50ZWdyYXRpb24pCiAgICAgICAgICAgICAgICAgICAgcC0+bV9zdXJmYWNlSW50ZWdyYXRpb24tPm9uU2V0Q2xpcGJvYXJkKHAtPm1fc2VsZWN0aW9uQnVmZmVyKTsKCiAgICAgICAgICAgICAgICByZXR1cm4gMTsKICAgICAgICAgICAgfTsKCiAgICAgICAgdnRlcm1fc3RhdGVfc2V0X3NlbGVjdGlvbl9jYWxsYmFja3ModnRzLCAmbV92dGVybVNlbGVjdGlvbkNhbGxiYWNrcywgdGhpcywgbnVsbHB0ciwgMjU2KTsKCiAgICAgICAgdnRlcm1fc3RhdGVfc2V0X2JvbGRfaGlnaGJyaWdodCh2dHMsIHRydWUpOwoKICAgICAgICBWVGVybUNvbG9yIGZnOwogICAgICAgIFZUZXJtQ29sb3IgYmc7CiAgICAgICAgdnRlcm1fY29sb3JfaW5kZXhlZCgmZmcsIENvbG9ySW5kZXg6OkZvcmVncm91bmQpOwogICAgICAgIHZ0ZXJtX2NvbG9yX2luZGV4ZWQoJmJnLCBDb2xvckluZGV4OjpCYWNrZ3JvdW5kKTsKICAgICAgICB2dGVybV9zdGF0ZV9zZXRfZGVmYXVsdF9jb2xvcnModnRzLCAmZmcsICZiZyk7CgogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgMTY7ICsraSkgewogICAgICAgICAgICBWVGVybUNvbG9yIGNvbDsKICAgICAgICAgICAgdnRlcm1fY29sb3JfaW5kZXhlZCgmY29sLCBpKTsKICAgICAgICAgICAgdnRlcm1fc3RhdGVfc2V0X3BhbGV0dGVfY29sb3IodnRzLCBpLCAmY29sKTsKICAgICAgICB9CgogICAgICAgIHZ0ZXJtX3NjcmVlbl9yZXNldChtX3Z0ZXJtU2NyZWVuLCAxKTsKICAgIH0KCiAgICBRU2l6ZSBsaXZlU2l6ZSgpIGNvbnN0CiAgICB7CiAgICAgICAgaW50IHJvd3M7CiAgICAgICAgaW50IGNvbHM7CiAgICAgICAgdnRlcm1fZ2V0X3NpemUobV92dGVybS5nZXQoKSwgJnJvd3MsICZjb2xzKTsKCiAgICAgICAgcmV0dXJuIFFTaXplKGNvbHMsIHJvd3MpOwogICAgfQoKICAgIHN0ZDo6dmFyaWFudDxpbnQsIFFDb2xvcj4gdG9WYXJpYW50Q29sb3IoY29uc3QgVlRlcm1Db2xvciAmY29sb3IpCiAgICB7CiAgICAgICAgaWYgKGNvbG9yLnR5cGUgJiBWVEVSTV9DT0xPUl9ERUZBVUxUX0JHKQogICAgICAgICAgICByZXR1cm4gQ29sb3JJbmRleDo6QmFja2dyb3VuZDsKICAgICAgICBlbHNlIGlmIChjb2xvci50eXBlICYgVlRFUk1fQ09MT1JfREVGQVVMVF9GRykKICAgICAgICAgICAgcmV0dXJuIENvbG9ySW5kZXg6OkZvcmVncm91bmQ7CiAgICAgICAgZWxzZSBpZiAoY29sb3IudHlwZSAmIFZURVJNX0NPTE9SX0lOREVYRUQpIHsKICAgICAgICAgICAgaWYgKGNvbG9yLmluZGV4ZWQuaWR4ID49IDE2KSB7CiAgICAgICAgICAgICAgICBWVGVybUNvbG9yIGMgPSBjb2xvcjsKICAgICAgICAgICAgICAgIHZ0ZXJtX3N0YXRlX2NvbnZlcnRfY29sb3JfdG9fcmdiKHZ0ZXJtX29idGFpbl9zdGF0ZShtX3Z0ZXJtLmdldCgpKSwgJmMpOwogICAgICAgICAgICAgICAgcmV0dXJuIHRvUUNvbG9yKGMpOwogICAgICAgICAgICB9CiAgICAgICAgICAgIHJldHVybiBjb2xvci5pbmRleGVkLmlkeDsKICAgICAgICB9IGVsc2UgaWYgKGNvbG9yLnR5cGUgPT0gVlRFUk1fQ09MT1JfUkdCKQogICAgICAgICAgICByZXR1cm4gdG9RQ29sb3IoY29sb3IpOwogICAgICAgIGVsc2UKICAgICAgICAgICAgcmV0dXJuIC0xOwogICAgfQoKICAgIFRlcm1pbmFsQ2VsbCB0b0NlbGwoY29uc3QgVlRlcm1TY3JlZW5DZWxsICZjZWxsKQogICAgewogICAgICAgIFRlcm1pbmFsQ2VsbCByZXN1bHQ7CiAgICAgICAgcmVzdWx0LndpZHRoID0gY2VsbC53aWR0aDsKICAgICAgICByZXN1bHQudGV4dCA9IFFTdHJpbmc6OmZyb21VY3M0KGNlbGwuY2hhcnMpOwoKICAgICAgICBjb25zdCBWVGVybUNvbG9yICpiZyA9ICZjZWxsLmJnOwogICAgICAgIGNvbnN0IFZUZXJtQ29sb3IgKmZnID0gJmNlbGwuZmc7CgogICAgICAgIGlmIChzdGF0aWNfY2FzdDxib29sPihjZWxsLmF0dHJzLnJldmVyc2UpKQogICAgICAgICAgICBzdGQ6OnN3YXAoZmcsIGJnKTsKCiAgICAgICAgcmVzdWx0LmJhY2tncm91bmRDb2xvciA9IHRvVmFyaWFudENvbG9yKCpiZyk7CiAgICAgICAgcmVzdWx0LmZvcmVncm91bmRDb2xvciA9IHRvVmFyaWFudENvbG9yKCpmZyk7CgogICAgICAgIHJlc3VsdC5ib2xkID0gY2VsbC5hdHRycy5ib2xkOwogICAgICAgIHJlc3VsdC5zdHJpa2VPdXQgPSBjZWxsLmF0dHJzLnN0cmlrZTsKCiAgICAgICAgaWYgKGNlbGwuYXR0cnMudW5kZXJsaW5lID4gMCkgewogICAgICAgICAgICByZXN1bHQudW5kZXJsaW5lU3R5bGUgPSBRVGV4dENoYXJGb3JtYXQ6Ok5vVW5kZXJsaW5lOwogICAgICAgICAgICBzd2l0Y2ggKGNlbGwuYXR0cnMudW5kZXJsaW5lKSB7CiAgICAgICAgICAgIGNhc2UgVlRFUk1fVU5ERVJMSU5FX1NJTkdMRToKICAgICAgICAgICAgICAgIHJlc3VsdC51bmRlcmxpbmVTdHlsZSA9IFFUZXh0Q2hhckZvcm1hdDo6U2luZ2xlVW5kZXJsaW5lOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgVlRFUk1fVU5ERVJMSU5FX0RPVUJMRToKICAgICAgICAgICAgICAgIC8vIFRPRE86IERvdWJsZSB1bmRlcmxpbmUKICAgICAgICAgICAgICAgIHJlc3VsdC51bmRlcmxpbmVTdHlsZSA9IFFUZXh0Q2hhckZvcm1hdDo6U2luZ2xlVW5kZXJsaW5lOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgVlRFUk1fVU5ERVJMSU5FX0NVUkxZOgogICAgICAgICAgICAgICAgcmVzdWx0LnVuZGVybGluZVN0eWxlID0gUVRleHRDaGFyRm9ybWF0OjpXYXZlVW5kZXJsaW5lOwogICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgIGNhc2UgVlRFUk1fVU5ERVJMSU5FX0RBU0hFRDoKICAgICAgICAgICAgICAgIHJlc3VsdC51bmRlcmxpbmVTdHlsZSA9IFFUZXh0Q2hhckZvcm1hdDo6RGFzaFVuZGVybGluZTsKICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICBjYXNlIFZURVJNX1VOREVSTElORV9ET1RURUQ6CiAgICAgICAgICAgICAgICByZXN1bHQudW5kZXJsaW5lU3R5bGUgPSBRVGV4dENoYXJGb3JtYXQ6OkRvdExpbmU7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0KCiAgICAgICAgcmVzdWx0LnN0cmlrZU91dCA9IGNlbGwuYXR0cnMuc3RyaWtlOwoKICAgICAgICByZXR1cm4gcmVzdWx0OwogICAgfQoKICAgIC8vIENhbGxiYWNrcyBmcm9tIHZ0ZXJtCiAgICB2b2lkIGludmFsaWRhdGUoVlRlcm1SZWN0IHJlY3QpCiAgICB7CiAgICAgICAgaWYgKCFtX2FsdHNjcmVlbikgewogICAgICAgICAgICByZWN0LnN0YXJ0X3JvdyArPSBtX3Njcm9sbGJhY2stPnNpemUoKTsKICAgICAgICAgICAgcmVjdC5lbmRfcm93ICs9IG1fc2Nyb2xsYmFjay0+c2l6ZSgpOwogICAgICAgIH0KCiAgICAgICAgZW1pdCBxLT5pbnZhbGlkYXRlZCgKICAgICAgICAgICAgUVJlY3R7UVBvaW50e3JlY3Quc3RhcnRfY29sLCByZWN0LnN0YXJ0X3Jvd30sIFFQb2ludHtyZWN0LmVuZF9jb2wsIHJlY3QuZW5kX3JvdyAtIDF9fSk7CiAgICB9CgogICAgaW50IHNiX3B1c2hsaW5lKGludCBjb2xzLCBjb25zdCBWVGVybVNjcmVlbkNlbGwgKmNlbGxzKQogICAgewogICAgICAgIG1fc2Nyb2xsYmFjay0+ZW1wbGFjZShjb2xzLCBjZWxscyk7CiAgICAgICAgZW1pdCBxLT5mdWxsU2l6ZUNoYW5nZWQocS0+ZnVsbFNpemUoKSk7CiAgICAgICAgcmV0dXJuIDE7CiAgICB9CgogICAgaW50IHNiX3BvcGxpbmUoaW50IGNvbHMsIFZUZXJtU2NyZWVuQ2VsbCAqY2VsbHMpCiAgICB7CiAgICAgICAgaWYgKG1fc2Nyb2xsYmFjay0+c2l6ZSgpID09IDApCiAgICAgICAgICAgIHJldHVybiAwOwoKICAgICAgICBtX3Njcm9sbGJhY2stPnBvcHRvKGNvbHMsIGNlbGxzKTsKICAgICAgICBlbWl0IHEtPmZ1bGxTaXplQ2hhbmdlZChxLT5mdWxsU2l6ZSgpKTsKICAgICAgICByZXR1cm4gMTsKICAgIH0KCiAgICBpbnQgc2JfY2xlYXIoKQogICAgewogICAgICAgIG1fc2Nyb2xsYmFjay0+Y2xlYXIoKTsKICAgICAgICBlbWl0IHEtPmZ1bGxTaXplQ2hhbmdlZChxLT5mdWxsU2l6ZSgpKTsKICAgICAgICByZXR1cm4gMTsKICAgIH0KCiAgICBpbnQgb3NjKGludCBjbWQsIGNvbnN0IFZUZXJtU3RyaW5nRnJhZ21lbnQgJmZyYWdtZW50KQogICAgewogICAgICAgIGlmIChtX3N1cmZhY2VJbnRlZ3JhdGlvbikgewogICAgICAgICAgICBtX3N1cmZhY2VJbnRlZ3JhdGlvbi0+b25Pc2MoY21kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge2ZyYWdtZW50LnN0ciwgZnJhZ21lbnQubGVufSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZyYWdtZW50LmluaXRpYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmFnbWVudC5maW5hbCk7CiAgICAgICAgfQoKICAgICAgICByZXR1cm4gMTsKICAgIH0KCiAgICBpbnQgc2V0VGVybWluYWxQcm9wZXJ0aWVzKFZUZXJtUHJvcCBwcm9wLCBWVGVybVZhbHVlICp2YWwpCiAgICB7CiAgICAgICAgc3dpdGNoIChwcm9wKSB7CiAgICAgICAgY2FzZSBWVEVSTV9QUk9QX0NVUlNPUlZJU0lCTEU6IHsKICAgICAgICAgICAgQ3Vyc29yIG9sZCA9IHEtPmN1cnNvcigpOwogICAgICAgICAgICBtX2N1cnNvci52aXNpYmxlID0gdmFsLT5ib29sZWFuOwogICAgICAgICAgICBxLT5jdXJzb3JDaGFuZ2VkKG9sZCwgcS0+Y3Vyc29yKCkpOwogICAgICAgICAgICBicmVhazsKICAgICAgICB9CiAgICAgICAgY2FzZSBWVEVSTV9QUk9QX0NVUlNPUkJMSU5LOiB7CiAgICAgICAgICAgIEN1cnNvciBvbGQgPSBxLT5jdXJzb3IoKTsKICAgICAgICAgICAgbV9jdXJzb3IuYmxpbmsgPSB2YWwtPmJvb2xlYW47CiAgICAgICAgICAgIGVtaXQgcS0+Y3Vyc29yQ2hhbmdlZChvbGQsIHEtPmN1cnNvcigpKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIGNhc2UgVlRFUk1fUFJPUF9DVVJTT1JTSEFQRTogewogICAgICAgICAgICBDdXJzb3Igb2xkID0gcS0+Y3Vyc29yKCk7CiAgICAgICAgICAgIG1fY3Vyc29yLnNoYXBlID0gKEN1cnNvcjo6U2hhcGUpIHZhbC0+bnVtYmVyOwogICAgICAgICAgICBlbWl0IHEtPmN1cnNvckNoYW5nZWQob2xkLCBxLT5jdXJzb3IoKSk7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIH0KICAgICAgICBjYXNlIFZURVJNX1BST1BfSUNPTk5BTUU6CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgVlRFUk1fUFJPUF9USVRMRToKICAgICAgICAgICAgaWYgKG1fc3VyZmFjZUludGVncmF0aW9uKQogICAgICAgICAgICAgICAgbV9zdXJmYWNlSW50ZWdyYXRpb24tPm9uVGl0bGUoUVN0cmluZzo6ZnJvbVV0ZjgodmFsLT5zdHJpbmcuc3RyLCB2YWwtPnN0cmluZy5sZW4pKTsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSBWVEVSTV9QUk9QX0FMVFNDUkVFTjoKICAgICAgICAgICAgbV9hbHRzY3JlZW4gPSB2YWwtPmJvb2xlYW47CiAgICAgICAgICAgIGVtaXQgcS0+YWx0c2NyZWVuQ2hhbmdlZChtX2FsdHNjcmVlbik7CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgVlRFUk1fUFJPUF9NT1VTRToKICAgICAgICAgICAgcUNEZWJ1Zyhsb2cpIDw8ICJJZ25vcmluZyBWVEVSTV9QUk9QX01PVVNFIiA8PCB2YWwtPm51bWJlcjsKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgY2FzZSBWVEVSTV9QUk9QX1JFVkVSU0U6CiAgICAgICAgICAgIHFDRGVidWcobG9nKSA8PCAiSWdub3JpbmcgVlRFUk1fUFJPUF9SRVZFUlNFIiA8PCB2YWwtPmJvb2xlYW47CiAgICAgICAgICAgIGJyZWFrOwogICAgICAgIGNhc2UgVlRFUk1fTl9QUk9QUzoKICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIHJldHVybiAxOwogICAgfQogICAgaW50IG1vdmVjdXJzb3IoVlRlcm1Qb3MgcG9zLCBWVGVybVBvcyBvbGRwb3MsIGludCB2aXNpYmxlKQogICAgewogICAgICAgIFFfVU5VU0VEKG9sZHBvcyk7CiAgICAgICAgQ3Vyc29yIG9sZEN1cnNvciA9IHEtPmN1cnNvcigpOwogICAgICAgIG1fY3Vyc29yLnBvc2l0aW9uID0ge3Bvcy5jb2wsIHBvcy5yb3d9OwogICAgICAgIG1fY3Vyc29yLnZpc2libGUgPSB2aXNpYmxlID4gMDsKICAgICAgICBxLT5jdXJzb3JDaGFuZ2VkKG9sZEN1cnNvciwgcS0+Y3Vyc29yKCkpOwogICAgICAgIHJldHVybiAxOwogICAgfQoKICAgIGNvbnN0IFZUZXJtU2NyZWVuQ2VsbCAqY2VsbEF0KGludCB4LCBpbnQgeSkKICAgIHsKICAgICAgICBpZiAoeSA8IDAgfHwgeCA8IDAgfHwgeSA+PSBxLT5mdWxsU2l6ZSgpLmhlaWdodCgpIHx8IHggPj0gbGl2ZVNpemUoKS53aWR0aCgpKSB7CiAgICAgICAgICAgIHFDV2FybmluZyhsb2cpIDw8ICJJbnZhbGlkIFBhcmFtZXRlciBmb3IgY2VsbEF0OiIgPDwgeCA8PCB5IDw8ICJsaXZlU2l6ZToiIDw8IGxpdmVTaXplKCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgPDwgImZ1bGxTaXplOiIgPDwgcS0+ZnVsbFNpemUoKTsKICAgICAgICAgICAgcmV0dXJuIG51bGxwdHI7CiAgICAgICAgfQoKICAgICAgICBpZiAoIW1fYWx0c2NyZWVuICYmIHkgPCBtX3Njcm9sbGJhY2stPnNpemUoKSkgewogICAgICAgICAgICBjb25zdCBhdXRvICZzYmwgPSBtX3Njcm9sbGJhY2stPmxpbmUoKG1fc2Nyb2xsYmFjay0+c2l6ZSgpIC0gMSkgLSB5KTsKICAgICAgICAgICAgaWYgKHggPCBzYmwuY29scygpKSB7CiAgICAgICAgICAgICAgICByZXR1cm4gc2JsLmNlbGwoeCk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIG51bGxwdHI7CiAgICAgICAgfQoKICAgICAgICBpZiAoIW1fYWx0c2NyZWVuKQogICAgICAgICAgICB5IC09IG1fc2Nyb2xsYmFjay0+c2l6ZSgpOwoKICAgICAgICBzdGF0aWMgVlRlcm1TY3JlZW5DZWxsIHJlZkNlbGx7fTsKICAgICAgICBWVGVybVBvcyB2dHB7eSwgeH07CiAgICAgICAgdnRlcm1fc2NyZWVuX2dldF9jZWxsKG1fdnRlcm1TY3JlZW4sIHZ0cCwgJnJlZkNlbGwpOwoKICAgICAgICByZXR1cm4gJnJlZkNlbGw7CiAgICB9CgogICAgc3RkOjp1bmlxdWVfcHRyPFZUZXJtLCB2b2lkICgqKShWVGVybSAqKT4gbV92dGVybTsKICAgIFZUZXJtU2NyZWVuICptX3Z0ZXJtU2NyZWVuOwogICAgVlRlcm1TY3JlZW5DYWxsYmFja3MgbV92dGVybVNjcmVlbkNhbGxiYWNrczsKICAgIFZUZXJtU3RhdGVGYWxsYmFja3MgbV92dGVybVN0YXRlRmFsbGJhY2tzOwoKICAgIFZUZXJtU2VsZWN0aW9uQ2FsbGJhY2tzIG1fdnRlcm1TZWxlY3Rpb25DYWxsYmFja3M7CgogICAgQ3Vyc29yIG1fY3Vyc29yOwogICAgUVN0cmluZyBtX2N1cnJlbnRDb21tYW5kOwoKICAgIGJvb2wgbV9hbHRzY3JlZW57ZmFsc2V9OwoKICAgIHN0ZDo6dW5pcXVlX3B0cjxTY3JvbGxiYWNrPiBtX3Njcm9sbGJhY2s7CgogICAgU3VyZmFjZUludGVncmF0aW9uICptX3N1cmZhY2VJbnRlZ3JhdGlvbntudWxscHRyfTsKCiAgICBUZXJtaW5hbFN1cmZhY2UgKnE7CiAgICBRVGltZXIgbV9kZWxheVdyaXRlVGltZXI7CiAgICBRQnl0ZUFycmF5IG1fd3JpdGVCdWZmZXI7CiAgICBRQnl0ZUFycmF5IG1fc2VsZWN0aW9uQnVmZmVyOwoKICAgIFRlcm1pbmFsU3VyZmFjZTo6V3JpdGVUb1B0eSBtX3dyaXRlVG9QdHk7Cn07CgpUZXJtaW5hbFN1cmZhY2U6OlRlcm1pbmFsU3VyZmFjZShRU2l6ZSBpbml0aWFsR3JpZFNpemUpCiAgICA6IGQoc3RkOjptYWtlX3VuaXF1ZTxUZXJtaW5hbFN1cmZhY2VQcml2YXRlPih0aGlzLCBpbml0aWFsR3JpZFNpemUpKQp7CiAgICBkLT5pbml0KCk7Cn0KClRlcm1pbmFsU3VyZmFjZTo6flRlcm1pbmFsU3VyZmFjZSgpID0gZGVmYXVsdDsKCmludCBUZXJtaW5hbFN1cmZhY2U6OmNlbGxXaWR0aEF0KGludCB4LCBpbnQgeSkgY29uc3QKewogICAgY29uc3QgVlRlcm1TY3JlZW5DZWxsICpjZWxsID0gZC0+Y2VsbEF0KHgsIHkpOwogICAgaWYgKCFjZWxsKQogICAgICAgIHJldHVybiAwOwogICAgcmV0dXJuIGNlbGwtPndpZHRoOwp9CgpRU2l6ZSBUZXJtaW5hbFN1cmZhY2U6OmxpdmVTaXplKCkgY29uc3QKewogICAgcmV0dXJuIGQtPmxpdmVTaXplKCk7Cn0KClFTaXplIFRlcm1pbmFsU3VyZmFjZTo6ZnVsbFNpemUoKSBjb25zdAp7CiAgICBpZiAoZC0+bV9hbHRzY3JlZW4pCiAgICAgICAgcmV0dXJuIGxpdmVTaXplKCk7CiAgICByZXR1cm4gUVNpemV7ZC0+bGl2ZVNpemUoKS53aWR0aCgpLCBkLT5saXZlU2l6ZSgpLmhlaWdodCgpICsgZC0+bV9zY3JvbGxiYWNrLT5zaXplKCl9Owp9CgpzdGQ6OnUzMnN0cmluZzo6dmFsdWVfdHlwZSBUZXJtaW5hbFN1cmZhY2U6OmZldGNoQ2hhckF0KGludCB4LCBpbnQgeSkgY29uc3QKewogICAgY29uc3QgVlRlcm1TY3JlZW5DZWxsICpjZWxsID0gZC0+Y2VsbEF0KHgsIHkpOwogICAgaWYgKCFjZWxsKQogICAgICAgIHJldHVybiAwOwoKICAgIGlmIChjZWxsLT53aWR0aCA9PSAwKQogICAgICAgIHJldHVybiAwOwoKICAgIFFTdHJpbmcgcyA9IFFTdHJpbmc6OmZyb21VY3M0KGNlbGwtPmNoYXJzLCA2KS5ub3JtYWxpemVkKFFTdHJpbmc6Ok5vcm1hbGl6YXRpb25Gb3JtX0MpOwogICAgY29uc3QgUUxpc3Q8dWludD4gdWNzNCA9IHMudG9VY3M0KCk7CiAgICByZXR1cm4gc3RkOjp1MzJzdHJpbmcodWNzNC5iZWdpbigpLCB1Y3M0LmVuZCgpKS5mcm9udCgpOwp9CgpUZXJtaW5hbENlbGwgVGVybWluYWxTdXJmYWNlOjpmZXRjaENlbGwoaW50IHgsIGludCB5KSBjb25zdAp7CiAgICBzdGF0aWMgVGVybWluYWxDZWxsIGVtcHR5Q2VsbHsxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge30sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7fSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29sb3JJbmRleDo6Rm9yZWdyb3VuZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvbG9ySW5kZXg6OkJhY2tncm91bmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBRVGV4dENoYXJGb3JtYXQ6Ok5vVW5kZXJsaW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFsc2V9OwoKICAgIGlmICh5IDwgMCB8fCB5ID49IGZ1bGxTaXplKCkuaGVpZ2h0KCkgfHwgeCA+PSBmdWxsU2l6ZSgpLndpZHRoKCkpIHsKICAgICAgICBxQ1dhcm5pbmcobG9nKSA8PCAiSW52YWxpZCBQYXJhbWV0ZXIgZm9yIGZldGNoQ2VsbDoiIDw8IHggPDwgeSA8PCAiZnVsbFNpemU6IiA8PCBmdWxsU2l6ZSgpOwogICAgICAgIHJldHVybiBlbXB0eUNlbGw7CiAgICB9CgogICAgY29uc3QgVlRlcm1TY3JlZW5DZWxsICpyZWZDZWxsID0gZC0+Y2VsbEF0KHgsIHkpOwogICAgaWYgKCFyZWZDZWxsKQogICAgICAgIHJldHVybiBlbXB0eUNlbGw7CgogICAgcmV0dXJuIGQtPnRvQ2VsbCgqcmVmQ2VsbCk7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpjbGVhckFsbCgpCnsKICAgIC8vIEZha2UgYSBzY3JvbGxiYWNrIGNsZWFyaW5nCiAgICBRQnl0ZUFycmF5IGRhdGF7Ilx4MWJbM0oifTsKICAgIHZ0ZXJtX2lucHV0X3dyaXRlKGQtPm1fdnRlcm0uZ2V0KCksIGRhdGEuY29uc3REYXRhKCksIGRhdGEuc2l6ZSgpKTsKCiAgICAvLyBTZW5kIEN0cmwrTCB3aGljaCB3aWxsIGNsZWFyIHRoZSBzY3JlZW4KICAgIGQtPm1fd3JpdGVUb1B0eShRQnl0ZUFycmF5KCJcZiIpKTsKfQoKdm9pZCBUZXJtaW5hbFN1cmZhY2U6OnJlc2l6ZShRU2l6ZSBuZXdTaXplKQp7CiAgICB2dGVybV9zZXRfc2l6ZShkLT5tX3Z0ZXJtLmdldCgpLCBuZXdTaXplLmhlaWdodCgpLCBuZXdTaXplLndpZHRoKCkpOwp9CgpRUG9pbnQgVGVybWluYWxTdXJmYWNlOjpwb3NUb0dyaWQoaW50IHBvcykgY29uc3QKewogICAgcmV0dXJuIHtwb3MgJSBkLT5saXZlU2l6ZSgpLndpZHRoKCksIHBvcyAvIGQtPmxpdmVTaXplKCkud2lkdGgoKX07Cn0KaW50IFRlcm1pbmFsU3VyZmFjZTo6Z3JpZFRvUG9zKFFQb2ludCBncmlkUG9zKSBjb25zdAp7CiAgICByZXR1cm4gZ3JpZFBvcy55KCkgKiBkLT5saXZlU2l6ZSgpLndpZHRoKCkgKyBncmlkUG9zLngoKTsKfQoKdm9pZCBUZXJtaW5hbFN1cmZhY2U6OmRhdGFGcm9tUHR5KGNvbnN0IFFCeXRlQXJyYXkgJmRhdGEpCnsKICAgIHZ0ZXJtX2lucHV0X3dyaXRlKGQtPm1fdnRlcm0uZ2V0KCksIGRhdGEuY29uc3REYXRhKCksIGRhdGEuc2l6ZSgpKTsKICAgIHZ0ZXJtX3NjcmVlbl9mbHVzaF9kYW1hZ2UoZC0+bV92dGVybVNjcmVlbik7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpmbHVzaCgpCnsKICAgIHZ0ZXJtX3NjcmVlbl9mbHVzaF9kYW1hZ2UoZC0+bV92dGVybVNjcmVlbik7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpwYXN0ZUZyb21DbGlwYm9hcmQoY29uc3QgUVN0cmluZyAmY2xpcGJvYXJkVGV4dCkKewogICAgaWYgKGNsaXBib2FyZFRleHQuaXNFbXB0eSgpKQogICAgICAgIHJldHVybjsKCiAgICB2dGVybV9rZXlib2FyZF9zdGFydF9wYXN0ZShkLT5tX3Z0ZXJtLmdldCgpKTsKICAgIGZvciAodW5zaWduZWQgaW50IGNoIDogY2xpcGJvYXJkVGV4dC50b1VjczQoKSkgewogICAgICAgIC8vIFdvcmthcm91bmQgZm9yIHdlaXJkIG5hbm8gYmVoYXZpb3IgdG8gY29ycmVjdGx5IHBhc3RlIG5ld2xpbmVzCiAgICAgICAgLy8gc2VlOiBodHRwOi8vc2F2YW5uYWguZ251Lm9yZy9idWdzLz80OTE3NgogICAgICAgIC8vIGFuZDogaHR0cHM6Ly9naXRodWIuY29tL2tvdmlkZ295YWwva2l0dHkvaXNzdWVzLzk5NAogICAgICAgIGlmIChjaCA9PSAnXG4nKQogICAgICAgICAgICBjaCA9ICdccic7CiAgICAgICAgdnRlcm1fa2V5Ym9hcmRfdW5pY2hhcihkLT5tX3Z0ZXJtLmdldCgpLCBjaCwgVlRFUk1fTU9EX05PTkUpOwogICAgfQogICAgdnRlcm1fa2V5Ym9hcmRfZW5kX3Bhc3RlKGQtPm1fdnRlcm0uZ2V0KCkpOwoKICAgIGlmICghZC0+bV9hbHRzY3JlZW4pIHsKICAgICAgICBlbWl0IHVuc2Nyb2xsKCk7CiAgICB9Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpzZW5kS2V5KFF0OjpLZXkga2V5KQp7CiAgICBpZiAoa2V5ID09IFF0OjpLZXlfRXNjYXBlKQogICAgICAgIHZ0ZXJtX2tleWJvYXJkX2tleShkLT5tX3Z0ZXJtLmdldCgpLCBWVEVSTV9LRVlfRVNDQVBFLCBWVEVSTV9NT0RfTk9ORSk7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpzZW5kS2V5KGNvbnN0IFFTdHJpbmcgJnRleHQpCnsKICAgIGZvciAoY29uc3QgdW5zaWduZWQgaW50IGNoIDogdGV4dC50b1VjczQoKSkKICAgICAgICB2dGVybV9rZXlib2FyZF91bmljaGFyKGQtPm1fdnRlcm0uZ2V0KCksIGNoLCBWVEVSTV9NT0RfTk9ORSk7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpzZW5kS2V5KFFLZXlFdmVudCAqZXZlbnQpCnsKICAgIGJvb2wga2V5cGFkID0gZXZlbnQtPm1vZGlmaWVycygpICYgUXQ6OktleXBhZE1vZGlmaWVyOwogICAgVlRlcm1Nb2RpZmllciBtb2QgPSBxdE1vZGlmaWVyVG9WVGVybShldmVudC0+bW9kaWZpZXJzKCkpOwogICAgVlRlcm1LZXkga2V5ID0gcXRLZXlUb1ZUZXJtKFF0OjpLZXkoZXZlbnQtPmtleSgpKSwga2V5cGFkKTsKCiAgICBpZiAoa2V5ICE9IFZURVJNX0tFWV9OT05FKSB7CiAgICAgICAgaWYgKG1vZCA9PSBWVEVSTV9NT0RfU0hJRlQgJiYgKGtleSA9PSBWVEVSTV9LRVlfRVNDQVBFIHx8IGtleSA9PSBWVEVSTV9LRVlfQkFDS1NQQUNFKSkKICAgICAgICAgICAgbW9kID0gVlRFUk1fTU9EX05PTkU7CgogICAgICAgIHZ0ZXJtX2tleWJvYXJkX2tleShkLT5tX3Z0ZXJtLmdldCgpLCBrZXksIG1vZCk7CiAgICB9IGVsc2UgaWYgKGV2ZW50LT50ZXh0KCkubGVuZ3RoKCkgPT0gMSkgewogICAgICAgIC8vIFRoaXMgbWFwcyB0byBkZWxldGUgd29yZCBhbmQgaXMgd2F5IHRvIGVhc3kgdG8gbWlzdGFrZW5seSB0eXBlCiAgICAgICAgLy8gICAgICAgIGlmIChldmVudC0+a2V5KCkgPT0gUXQ6OktleV9TcGFjZSAmJiBtb2QgPT0gVlRFUk1fTU9EX1NISUZUKQogICAgICAgIC8vICAgICAgICAgICAgbW9kID0gVlRFUk1fTU9EX05PTkU7CgogICAgICAgIC8vIFBlciBodHRwczovL2dpdGh1Yi5jb20vanVzdGlubWsvbmVvdmltL2NvbW1pdC8zMTdkNWNhN2IwZjkyZWY0MmRlOTg5YjM1NTZjYTk1MDNmMGEzYmY2CiAgICAgICAgLy8gbGlidnRlcm0gcHJlZmVycyB3ZSBzZW5kIHRoZSBmdWxsIGtleWNvZGUgcmF0aGVyIHRoYW4gc2VuZGluZyB0aGUKICAgICAgICAvLyBjdHJsIG1vZGlmaWVyLiAgVGhpcyBoZWxwcyB3aXRoIG5jdXJzZXMgYXBwbGljYXRpb25zIHdoaWNoIG90aGVyd2lzZQogICAgICAgIC8vIGRvIG5vdCByZWNvZ25pemUgY3RybCs8a2V5PiBhbmQgaW4gdGhlIHNoZWxsIGZvciBnZXR0aW5nIGNvbW1vbiBjb250cm9sIGNoYXJhY3RlcnMKICAgICAgICAvLyBsaWtlIGN0cmwraSBmb3IgdGFiIG9yIGN0cmwraiBmb3IgbmV3bGluZS4KCiAgICAgICAgLy8gV29ya2Fyb3VuZCBmb3IgIkFMVCtTSElGVCsvIiAoXCBvbiBnZXJtYW4gbWFjIGtleWJvYXJkcykKICAgICAgICBpZiAobW9kID09IChWVEVSTV9NT0RfU0hJRlQgfCBWVEVSTV9NT0RfQUxUKSAmJiBldmVudC0+a2V5KCkgPT0gUXQ6OktleV9TbGFzaCkgewogICAgICAgICAgICBtb2QgPSBWVEVSTV9NT0RfTk9ORTsKICAgICAgICB9CgogICAgICAgIHZ0ZXJtX2tleWJvYXJkX3VuaWNoYXIoZC0+bV92dGVybS5nZXQoKSwgZXZlbnQtPnRleHQoKS50b1VjczQoKVswXSwgVlRFUk1fTU9EX05PTkUpOwogICAgfSBlbHNlIGlmIChtb2QgPT0gVlRFUk1fTU9EX0NUUkwgJiYgZXZlbnQtPmtleSgpID49IFF0OjpLZXlfQSAmJiBldmVudC0+a2V5KCkgPCBRdDo6S2V5X1opIHsKICAgICAgICB2dGVybV9rZXlib2FyZF91bmljaGFyKGQtPm1fdnRlcm0uZ2V0KCksICdhJyArIChldmVudC0+a2V5KCkgLSBRdDo6S2V5X0EpLCBtb2QpOwogICAgfQp9CgpDdXJzb3IgVGVybWluYWxTdXJmYWNlOjpjdXJzb3IoKSBjb25zdAp7CiAgICBDdXJzb3IgY3Vyc29yID0gZC0+bV9jdXJzb3I7CiAgICBpZiAoIWQtPm1fYWx0c2NyZWVuKQogICAgICAgIGN1cnNvci5wb3NpdGlvbi5zZXRZKGN1cnNvci5wb3NpdGlvbi55KCkgKyBkLT5tX3Njcm9sbGJhY2stPnNpemUoKSk7CgogICAgcmV0dXJuIGN1cnNvcjsKfQoKU3VyZmFjZUludGVncmF0aW9uICpUZXJtaW5hbFN1cmZhY2U6OnN1cmZhY2VJbnRlZ3JhdGlvbigpIGNvbnN0CnsKICAgIHJldHVybiBkLT5tX3N1cmZhY2VJbnRlZ3JhdGlvbjsKfQoKdm9pZCBUZXJtaW5hbFN1cmZhY2U6OnNldFN1cmZhY2VJbnRlZ3JhdGlvbihTdXJmYWNlSW50ZWdyYXRpb24gKnN1cmZhY2VJbnRlZ3JhdGlvbikKewogICAgZC0+bV9zdXJmYWNlSW50ZWdyYXRpb24gPSBzdXJmYWNlSW50ZWdyYXRpb247Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjptb3VzZU1vdmUoUVBvaW50IHBvcywgUXQ6OktleWJvYXJkTW9kaWZpZXJzIG1vZGlmaWVycykKewogICAgdnRlcm1fbW91c2VfbW92ZShkLT5tX3Z0ZXJtLmdldCgpLCBwb3MueSgpLCBwb3MueCgpLCBxdE1vZGlmaWVyVG9WVGVybShtb2RpZmllcnMpKTsKfQoKdm9pZCBUZXJtaW5hbFN1cmZhY2U6Om1vdXNlQnV0dG9uKFF0OjpNb3VzZUJ1dHRvbiBidXR0b24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib29sIHByZXNzZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBRdDo6S2V5Ym9hcmRNb2RpZmllcnMgbW9kaWZpZXJzKQp7CiAgICBpbnQgYnRuSWR4ID0gMDsKICAgIHN3aXRjaCAoYnV0dG9uKSB7CiAgICBjYXNlIFF0OjpMZWZ0QnV0dG9uOgogICAgICAgIGJ0bklkeCA9IDE7CiAgICAgICAgYnJlYWs7CiAgICBjYXNlIFF0OjpSaWdodEJ1dHRvbjoKICAgICAgICBidG5JZHggPSAzOwogICAgICAgIGJyZWFrOwogICAgY2FzZSBRdDo6TWlkZGxlQnV0dG9uOgogICAgICAgIGJ0bklkeCA9IDI7CiAgICAgICAgYnJlYWs7CiAgICBjYXNlIFF0OjpFeHRyYUJ1dHRvbjE6CiAgICAgICAgYnRuSWR4ID0gNDsKICAgICAgICBicmVhazsKICAgIGNhc2UgUXQ6OkV4dHJhQnV0dG9uMjoKICAgICAgICBidG5JZHggPSA1OwogICAgICAgIGJyZWFrOwogICAgZGVmYXVsdDoKICAgICAgICByZXR1cm47CiAgICB9CgogICAgdnRlcm1fbW91c2VfYnV0dG9uKGQtPm1fdnRlcm0uZ2V0KCksIGJ0bklkeCwgcHJlc3NlZCwgcXRNb2RpZmllclRvVlRlcm0obW9kaWZpZXJzKSk7Cn0KCnZvaWQgVGVybWluYWxTdXJmYWNlOjpzZXRXcml0ZVRvUHR5KFdyaXRlVG9QdHkgd3JpdGVUb1B0eSkKewogICAgZC0+bV93cml0ZVRvUHR5ID0gd3JpdGVUb1B0eTsKfQoKQ2VsbEl0ZXJhdG9yIFRlcm1pbmFsU3VyZmFjZTo6YmVnaW4oKSBjb25zdAp7CiAgICBhdXRvIHJlcyA9IENlbGxJdGVyYXRvcih0aGlzLCB7MCwgMH0pOwogICAgcmVzLm1fc3RhdGUgPSBDZWxsSXRlcmF0b3I6OlN0YXRlOjpCRUdJTjsKICAgIHJldHVybiByZXM7Cn0KCkNlbGxJdGVyYXRvciBUZXJtaW5hbFN1cmZhY2U6OmVuZCgpIGNvbnN0CnsKICAgIHJldHVybiBDZWxsSXRlcmF0b3IodGhpcyk7Cn0KCnN0ZDo6cmV2ZXJzZV9pdGVyYXRvcjxDZWxsSXRlcmF0b3I+IFRlcm1pbmFsU3VyZmFjZTo6cmJlZ2luKCkgY29uc3QKewogICAgcmV0dXJuIHN0ZDo6bWFrZV9yZXZlcnNlX2l0ZXJhdG9yKGVuZCgpKTsKfQoKc3RkOjpyZXZlcnNlX2l0ZXJhdG9yPENlbGxJdGVyYXRvcj4gVGVybWluYWxTdXJmYWNlOjpyZW5kKCkgY29uc3QKewogICAgcmV0dXJuIHN0ZDo6bWFrZV9yZXZlcnNlX2l0ZXJhdG9yKGJlZ2luKCkpOwp9CgpDZWxsSXRlcmF0b3IgVGVybWluYWxTdXJmYWNlOjppdGVyYXRvckF0KFFQb2ludCBwb3MpIGNvbnN0CnsKICAgIHJldHVybiBDZWxsSXRlcmF0b3IodGhpcywgcG9zKTsKfQpDZWxsSXRlcmF0b3IgVGVybWluYWxTdXJmYWNlOjppdGVyYXRvckF0KGludCBwb3MpIGNvbnN0CnsKICAgIHJldHVybiBDZWxsSXRlcmF0b3IodGhpcywgcG9zKTsKfQoKc3RkOjpyZXZlcnNlX2l0ZXJhdG9yPENlbGxJdGVyYXRvcj4gVGVybWluYWxTdXJmYWNlOjpySXRlcmF0b3JBdChRUG9pbnQgcG9zKSBjb25zdAp7CiAgICByZXR1cm4gc3RkOjptYWtlX3JldmVyc2VfaXRlcmF0b3IoaXRlcmF0b3JBdChwb3MpKTsKfQoKc3RkOjpyZXZlcnNlX2l0ZXJhdG9yPENlbGxJdGVyYXRvcj4gVGVybWluYWxTdXJmYWNlOjpySXRlcmF0b3JBdChpbnQgcG9zKSBjb25zdAp7CiAgICByZXR1cm4gc3RkOjptYWtlX3JldmVyc2VfaXRlcmF0b3IoaXRlcmF0b3JBdChwb3MpKTsKfQoKfSAvLyBuYW1lc3BhY2UgVGVybWluYWxTb2x1dGlvbgo=\a\n" + +read -p " ⎆ Press enter to continue " -n1 -s +echo +echo