#ifndef KECCAK_DETAIL_HPP
#define KECCAK_DETAIL_HPP
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <array>
namespace keccak
{
namespace detail
{
template <unsigned long long A, unsigned long long B>
struct static_max
{
static const auto value = A > B ? A : B;
};
template <unsigned N, unsigned C = 0>
struct static_log2
{
static const unsigned value = static_log2<N / 2, C + 1>::value;
};
template <unsigned C>
struct static_log2<1, C>
{
static const unsigned value = C;
};
template <unsigned C>
struct static_log2<0, C>
{
static_assert(C >= 1, "Log2 result is not an integer.");
static_assert(C < 1, "Log2 result is not an integer.");
};
template <typename StateType, typename LaneType>
void round(StateType& s, LaneType round_constant);
template <unsigned Rounds, typename StateType>
void keccak_f(StateType& state);
template <typename LaneType, std::size_t Capacity>
class keccak_state
{
public:
typedef LaneType lane_type;
typedef lane_type plane_type[5];
typedef std::array<plane_type, 5> state_type;
static const std::size_t byte_bits = 8;
static const auto width = sizeof(lane_type) * byte_bits;
static const auto capacity = Capacity;
static const auto rate = 25 * width - capacity;
static const auto byte_width = width / byte_bits;
static const auto byte_capacity = capacity / byte_bits;
static const auto byte_rate = rate / byte_bits;
static const auto rounds = 12 + 2 * static_log2<width>::value;
static_assert(width % byte_bits == 0, "Sub-byte hacks are not supported.");
static_assert(capacity % byte_bits == 0, "Sub-byte hacks are not supported.");
static_assert(rate % byte_bits == 0, "Sub-byte hacks are not supported.");
static_assert(rate % width == 0, "Rate / width combination impossible.");
static_assert(byte_rate % byte_width == 0, "Rate / width combination not supported.");
static_assert(capacity < 25 * width, "Capacity too high.");
private:
state_type state_;
public:
keccak_state()
: state_()
{}
const plane_type& operator [] (std::size_t i) const
{
return state_[i];
}
plane_type& operator [] (std::size_t i)
{
return state_[i];
}
const lane_type* data() const
{
return state_.data()[0];
}
lane_type* data()
{
return state_.data()[0];
}
void transform()
{
keccak_f<rounds>(state_);
}
};
template <typename StateType>
class sponge_absorber
{
public:
typedef StateType state_type;
typedef typename state_type::lane_type lane_type;
private:
state_type state_;
std::size_t bytes_absorbed_;
public:
sponge_absorber()
: bytes_absorbed_()
{}
sponge_absorber(const void* data, std::size_t size)
: bytes_absorbed_()
{
(*this)(data, size);
}
void operator () (const void* data, std::size_t size)
{
auto data_bytes = static_cast<const std::uint8_t*>(data);
while (size != 0)
{
while (bytes_absorbed_ == 0 && size >= state_type::byte_rate)
{
for (std::size_t i = 0; i != state_type::byte_rate / state_type::byte_width; ++i)
{
lane_type lane;
std::memcpy(&lane, data_bytes + i * state_type::byte_width, state_type::byte_width);
*(state_[0] + i) ^= lane;
}
data_bytes += state_type::byte_rate;
size -= state_type::byte_rate;
state_.transform();
}
if (size != 0)
{
reinterpret_cast<std::uint8_t*>(state_.data())[bytes_absorbed_] ^= *data_bytes;
++data_bytes;
--size;
if (++bytes_absorbed_ == state_type::byte_rate)
{
state_.transform();
bytes_absorbed_ = 0;
}
}
}
}
std::size_t bytes_absorbed() const
{
return bytes_absorbed_;
}
const state_type& internal_state() const
{
return state_;
}
state_type& internal_state()
{
return state_;
}
};
template <typename StateType>
class sponge_squeezer
{
public:
typedef StateType state_type;
typedef typename state_type::lane_type lane_type;
private:
state_type state_;
std::size_t bytes_squeezed_;
public:
sponge_squeezer(sponge_absorber<state_type> absorber)
: state_(absorber.internal_state())
, bytes_squeezed_()
{
reinterpret_cast<std::uint8_t*>(state_.data())[absorber.bytes_absorbed()] ^= 1u;
reinterpret_cast<std::uint8_t*>(state_.data())[state_type::byte_rate - 1] ^= 128u;
state_.transform();
}
void operator () (void* buf, std::size_t size)
{
auto buf_bytes = static_cast<std::uint8_t*>(buf);
while (size != 0)
{
while (bytes_squeezed_ == 0 && size >= state_type::byte_rate)
{
std::memcpy(buf_bytes, state_.data(), state_type::byte_rate);
buf_bytes += state_type::byte_rate;
size -= state_type::byte_rate;
state_.transform();
}
if (size != 0)
{
const auto copy_size = std::min(size, state_type::byte_rate - bytes_squeezed_);
const auto state_bytes = reinterpret_cast<std::uint8_t*>(state_.data());
std::memcpy(buf_bytes, state_bytes + bytes_squeezed_, copy_size);
buf_bytes += copy_size;
size -= copy_size;
bytes_squeezed_ += copy_size;
if (bytes_squeezed_ == state_type::byte_rate)
{
state_.transform();
bytes_squeezed_ = 0;
}
}
}
}
std::size_t bytes_squeezed() const
{
return bytes_squeezed_;
}
const state_type& internal_state() const
{
return state_;
}
state_type& internal_state()
{
return state_;
}
};
const std::uint64_t round_constants[24] =
{
0x0000000000000001ull,
0x0000000000008082ull,
0x800000000000808Aull,
0x8000000080008000ull,
0x000000000000808Bull,
0x0000000080000001ull,
0x8000000080008081ull,
0x8000000000008009ull,
0x000000000000008Aull,
0x0000000000000088ull,
0x0000000080008009ull,
0x000000008000000Aull,
0x000000008000808Bull,
0x800000000000008Bull,
0x8000000000008089ull,
0x8000000000008003ull,
0x8000000000008002ull,
0x8000000000000080ull,
0x000000000000800Aull,
0x800000008000000Aull,
0x8000000080008081ull,
0x8000000000008080ull,
0x0000000080000001ull,
0x8000000080008008ull,
};
template <unsigned Rounds, typename StateType>
void keccak_f(StateType& state)
{
for (unsigned i = 0; i != Rounds; ++i)
{
round(state, round_constants[i]);
}
}
template <unsigned N, typename Word>
Word shl(Word w)
{
return w << (N);
}
template <unsigned N, typename Word>
Word shr(Word w)
{
return w >> (N);
}
template <unsigned N, typename Word>
Word rotr(Word w)
{
return shr<N>(w) | shl<sizeof(Word) * 8 - N>(w);
}
template <unsigned N, typename Word>
Word rotl(Word w)
{
return shl<N>(w) | shr<sizeof(Word) * 8 - N>(w);
}
template <typename Word>
Word rotr(Word w, unsigned n)
{
return (w >> n) | (w << (sizeof(Word) * 8 - n));
}
template <typename Word>
Word rotl(Word w, unsigned n)
{
return (w << n) | (w >> (sizeof(Word) * 8 - n));
}
typedef unsigned rotation_offset_type;
const rotation_offset_type roffset_0_0 = 0;
const rotation_offset_type roffset_0_1 = 36;
const rotation_offset_type roffset_0_2 = 3;
const rotation_offset_type roffset_0_3 = 41;
const rotation_offset_type roffset_0_4 = 18;
const rotation_offset_type roffset_1_0 = 1;
const rotation_offset_type roffset_1_1 = 44;
const rotation_offset_type roffset_1_2 = 10;
const rotation_offset_type roffset_1_3 = 45;
const rotation_offset_type roffset_1_4 = 2;
const rotation_offset_type roffset_2_0 = 62;
const rotation_offset_type roffset_2_1 = 6;
const rotation_offset_type roffset_2_2 = 43;
const rotation_offset_type roffset_2_3 = 15;
const rotation_offset_type roffset_2_4 = 61;
const rotation_offset_type roffset_3_0 = 28;
const rotation_offset_type roffset_3_1 = 55;
const rotation_offset_type roffset_3_2 = 25;
const rotation_offset_type roffset_3_3 = 21;
const rotation_offset_type roffset_3_4 = 56;
const rotation_offset_type roffset_4_0 = 27;
const rotation_offset_type roffset_4_1 = 20;
const rotation_offset_type roffset_4_2 = 39;
const rotation_offset_type roffset_4_3 = 8;
const rotation_offset_type roffset_4_4 = 14;
template <typename StateType, typename LaneType>
void round(StateType& s, LaneType round_constant)
{
auto c0 = s[0][0] ^ s[1][0] ^ s[2][0] ^ s[3][0] ^ s[4][0];
auto c1 = s[0][1] ^ s[1][1] ^ s[2][1] ^ s[3][1] ^ s[4][1];
auto c2 = s[0][2] ^ s[1][2] ^ s[2][2] ^ s[3][2] ^ s[4][2];
auto c3 = s[0][3] ^ s[1][3] ^ s[2][3] ^ s[3][3] ^ s[4][3];
auto c4 = s[0][4] ^ s[1][4] ^ s[2][4] ^ s[3][4] ^ s[4][4];
auto d0 = c4 ^ rotl<1>(c1);
auto d1 = c0 ^ rotl<1>(c2);
auto d2 = c1 ^ rotl<1>(c3);
auto d3 = c2 ^ rotl<1>(c4);
auto d4 = c3 ^ rotl<1>(c0);
s[0][0] ^= d0;
s[0][1] ^= d1;
s[0][2] ^= d2;
s[0][3] ^= d3;
auto s00 = (s[0][0]); /* rotl<roffset_0_0> */
auto s20 = rotl<roffset_1_0>(s[0][1]);
auto s40 = rotl<roffset_2_0>(s[0][2]);
auto s10 = rotl<roffset_3_0>(s[0][3]);
s[0][4] ^= d4;
s[1][0] ^= d0;
s[1][1] ^= d1;
s[1][2] ^= d2;
auto s30 = rotl<roffset_4_0>(s[0][4]);
auto s31 = rotl<roffset_0_1>(s[1][0]);
auto s01 = rotl<roffset_1_1>(s[1][1]);
auto s21 = rotl<roffset_2_1>(s[1][2]);
s[1][3] ^= d3;
s[1][4] ^= d4;
s[2][0] ^= d0;
s[2][1] ^= d1;
auto s41 = rotl<roffset_3_1>(s[1][3]);
auto s11 = rotl<roffset_4_1>(s[1][4]);
auto s12 = rotl<roffset_0_2>(s[2][0]);
auto s32 = rotl<roffset_1_2>(s[2][1]);
s[2][2] ^= d2;
s[2][3] ^= d3;
s[2][4] ^= d4;
s[3][0] ^= d0;
auto s02 = rotl<roffset_2_2>(s[2][2]);
auto s22 = rotl<roffset_3_2>(s[2][3]);
auto s42 = rotl<roffset_4_2>(s[2][4]);
auto s43 = rotl<roffset_0_3>(s[3][0]);
s[3][1] ^= d1;
s[3][2] ^= d2;
s[3][3] ^= d3;
s[3][4] ^= d4;
auto s13 = rotl<roffset_1_3>(s[3][1]);
auto s33 = rotl<roffset_2_3>(s[3][2]);
auto s03 = rotl<roffset_3_3>(s[3][3]);
auto s23 = rotl<roffset_4_3>(s[3][4]);
s[4][0] ^= d0;
s[4][1] ^= d1;
s[4][2] ^= d2;
s[4][3] ^= d3;
auto s24 = rotl<roffset_0_4>(s[4][0]);
auto s44 = rotl<roffset_1_4>(s[4][1]);
auto s14 = rotl<roffset_2_4>(s[4][2]);
auto s34 = rotl<roffset_3_4>(s[4][3]);
s[4][4] ^= d4;
auto s04 = rotl<roffset_4_4>(s[4][4]);
//
s[0][0] = s00 ^ (~s01 & s02);
s[0][1] = s01 ^ (~s02 & s03);
s[0][2] = s02 ^ (~s03 & s04);
s[0][3] = s03 ^ (~s04 & s00);
s[0][4] = s04 ^ (~s00 & s01);
s[1][0] = s10 ^ (~s11 & s12);
s[1][1] = s11 ^ (~s12 & s13);
s[1][2] = s12 ^ (~s13 & s14);
s[1][3] = s13 ^ (~s14 & s10);
s[1][4] = s14 ^ (~s10 & s11);
s[2][0] = s20 ^ (~s21 & s22);
s[2][1] = s21 ^ (~s22 & s23);
s[2][2] = s22 ^ (~s23 & s24);
s[2][3] = s23 ^ (~s24 & s20);
s[2][4] = s24 ^ (~s20 & s21);
s[3][0] = s30 ^ (~s31 & s32);
s[3][1] = s31 ^ (~s32 & s33);
s[3][2] = s32 ^ (~s33 & s34);
s[3][3] = s33 ^ (~s34 & s30);
s[3][4] = s34 ^ (~s30 & s31);
s[4][0] = s40 ^ (~s41 & s42);
s[4][1] = s41 ^ (~s42 & s43);
s[4][2] = s42 ^ (~s43 & s44);
s[4][3] = s43 ^ (~s44 & s40);
s[4][4] = s44 ^ (~s40 & s41);
s[0][0] ^= round_constant;
}
}
}
#endif
#ifndef KECCAK_HPP
#define KECCAK_HPP
#include <array>
#include <cstdint>
#include <limits>
//#include "keccak_detail.hpp"
namespace keccak
{
template <std::size_t CollisionResistance, std::size_t PreimageResistance>
class basic_hasher
{
public:
static const auto collision_resistance = CollisionResistance;
static const auto preimage_resistance = PreimageResistance;
static const auto capacity = detail::static_max<collision_resistance * 2, preimage_resistance * 2>::value;
static const auto hash_size = detail::static_max<collision_resistance * 2 / 8, preimage_resistance / 8>::value;
typedef detail::keccak_state<std::uint64_t, capacity> state_type;
typedef std::array<std::uint8_t, hash_size> hash_type;
private:
detail::sponge_absorber<state_type> absorb_;
public:
void update(const void* data, std::size_t size)
{
absorb_(data, size);
}
void finish(void* buf, std::size_t size)
{
detail::sponge_squeezer<state_type> squeeze(std::move(absorb_));
squeeze(buf, size);
*this = basic_hasher();
}
hash_type finish()
{
hash_type hash;
finish(hash.data(), hash.size());
return hash;
}
};
typedef basic_hasher<112, 224> sha3_244_hasher;
typedef basic_hasher<128, 256> sha3_256_hasher;
typedef basic_hasher<192, 384> sha3_384_hasher;
typedef basic_hasher<256, 512> sha3_512_hasher;
typedef basic_hasher<112, 112> s112_hasher;
typedef basic_hasher<128, 128> s128_hasher;
typedef basic_hasher<192, 192> s192_hasher;
typedef basic_hasher<256, 256> s256_hasher;
template <std::size_t SecurityStrength>
class basic_stream_crypter
{
public:
static const auto security_strength = SecurityStrength;
typedef detail::keccak_state<std::uint64_t, security_strength * 2> state_type;
typedef typename state_type::lane_type lane_type;
private:
detail::sponge_squeezer<state_type> squeeze_;
public:
basic_stream_crypter(const void* key, std::size_t keylen)
: squeeze_(detail::sponge_absorber<state_type>(key, keylen))
{}
void operator () (void* buf, const void* data, std::size_t size)
{
auto dptr = static_cast<const std::uint8_t*>(data);
auto bptr = static_cast<std::uint8_t*>(buf);
auto msize = size / sizeof(lane_type);
auto rsize = size % sizeof(lane_type);
auto shift = apply<lane_type>(bptr, dptr, msize);
apply<std::uint8_t>(bptr + shift, dptr + shift, rsize);
}
private:
template <typename LaneType>
std::size_t apply(void* buf, const void* data, std::size_t size)
{
auto dptr = static_cast<const std::uint8_t*>(data);
auto bptr = static_cast<std::uint8_t*>(buf);
for (auto i = 0; i != size; ++i)
{
LaneType l1, l2;
squeeze_(&l1, sizeof l1);
std::memcpy(&l2, dptr + i * sizeof(LaneType), sizeof l2);
l1 ^= l2;
std::memcpy(bptr + i * sizeof(LaneType), &l1, sizeof l1);
}
return size * sizeof(LaneType);
}
};
}
#endif
#include <iostream>
#include <string>
void dump(const void* memory, std::size_t size)
{
static const char table[256][3] =
{
"00", "01", "02", "03", "04", "05", "06", "07",
"08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17",
"18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27",
"28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
"30", "31", "32", "33", "34", "35", "36", "37",
"38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
"40", "41", "42", "43", "44", "45", "46", "47",
"48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
"50", "51", "52", "53", "54", "55", "56", "57",
"58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
"60", "61", "62", "63", "64", "65", "66", "67",
"68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
"70", "71", "72", "73", "74", "75", "76", "77",
"78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
"80", "81", "82", "83", "84", "85", "86", "87",
"88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
"90", "91", "92", "93", "94", "95", "96", "97",
"98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
"a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
"b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7",
"c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"d8", "d9", "da", "db", "dc", "dd", "de", "df",
"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7",
"e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
};
const unsigned char* p = static_cast<const unsigned char*>(memory);
for (; size--; ++p)
std::cout << table[*p];
std::cout << '\n';
}
int main()
{
std::cout << "Key: ";
std::string key;
std::getline(std::cin, key);
keccak::basic_stream_crypter<128> encrypt(key.data(), key.size());
keccak::basic_stream_crypter<128> decrypt(key.data(), key.size());
std::string msg;
while (std::cout << "Message: " && std::getline(std::cin, msg))
{
std::string enc(msg.size(), ' ');
encrypt(&enc[0], msg.data(), msg.size());
std::cout << "Encrypted: ";
dump(enc.data(), enc.size());
std::string dec(msg.size(), ' ');
decrypt(&dec[0], enc.data(), enc.size());
std::cout << "Decrypted: " << dec << '\n';
}
}
I2lmbmRlZiBLRUNDQUtfREVUQUlMX0hQUAojZGVmaW5lIEtFQ0NBS19ERVRBSUxfSFBQCgojaW5jbHVkZSA8Y3N0ZGRlZj4KI2luY2x1ZGUgPGNzdGRpbnQ+CiNpbmNsdWRlIDxjc3RyaW5nPgojaW5jbHVkZSA8YXJyYXk+CgpuYW1lc3BhY2Uga2VjY2FrCnsKCW5hbWVzcGFjZSBkZXRhaWwKCXsKCQl0ZW1wbGF0ZSA8dW5zaWduZWQgbG9uZyBsb25nIEEsIHVuc2lnbmVkIGxvbmcgbG9uZyBCPgoJCXN0cnVjdCBzdGF0aWNfbWF4CgkJewoJCQlzdGF0aWMgY29uc3QgYXV0byB2YWx1ZSA9IEEgPiBCID8gQSA6IEI7CgkJfTsKCgkJdGVtcGxhdGUgPHVuc2lnbmVkIE4sIHVuc2lnbmVkIEMgPSAwPgoJCXN0cnVjdCBzdGF0aWNfbG9nMgoJCXsKCQkJc3RhdGljIGNvbnN0IHVuc2lnbmVkIHZhbHVlID0gc3RhdGljX2xvZzI8TiAvIDIsIEMgKyAxPjo6dmFsdWU7CgkJfTsKCgkJdGVtcGxhdGUgPHVuc2lnbmVkIEM+CgkJc3RydWN0IHN0YXRpY19sb2cyPDEsIEM+CgkJewoJCQlzdGF0aWMgY29uc3QgdW5zaWduZWQgdmFsdWUgPSBDOwoJCX07CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBDPgoJCXN0cnVjdCBzdGF0aWNfbG9nMjwwLCBDPgoJCXsKCQkJc3RhdGljX2Fzc2VydChDID49IDEsICJMb2cyIHJlc3VsdCBpcyBub3QgYW4gaW50ZWdlci4iKTsKCQkJc3RhdGljX2Fzc2VydChDIDwgMSwgIkxvZzIgcmVzdWx0IGlzIG5vdCBhbiBpbnRlZ2VyLiIpOwoJCX07CgoJCXRlbXBsYXRlIDx0eXBlbmFtZSBTdGF0ZVR5cGUsIHR5cGVuYW1lIExhbmVUeXBlPgoJCXZvaWQgcm91bmQoU3RhdGVUeXBlJiBzLCBMYW5lVHlwZSByb3VuZF9jb25zdGFudCk7CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBSb3VuZHMsIHR5cGVuYW1lIFN0YXRlVHlwZT4KCQl2b2lkIGtlY2Nha19mKFN0YXRlVHlwZSYgc3RhdGUpOwoKCQl0ZW1wbGF0ZSA8dHlwZW5hbWUgTGFuZVR5cGUsIHN0ZDo6c2l6ZV90IENhcGFjaXR5PgoJCWNsYXNzIGtlY2Nha19zdGF0ZQoJCXsKCQlwdWJsaWM6CgkJCXR5cGVkZWYgTGFuZVR5cGUgbGFuZV90eXBlOwoJCQl0eXBlZGVmIGxhbmVfdHlwZSBwbGFuZV90eXBlWzVdOwoJCQl0eXBlZGVmIHN0ZDo6YXJyYXk8cGxhbmVfdHlwZSwgNT4gc3RhdGVfdHlwZTsKCgkJCXN0YXRpYyBjb25zdCBzdGQ6OnNpemVfdCBieXRlX2JpdHMgPSA4OwoKCQkJc3RhdGljIGNvbnN0IGF1dG8gd2lkdGggPSBzaXplb2YobGFuZV90eXBlKSAqIGJ5dGVfYml0czsKCQkJc3RhdGljIGNvbnN0IGF1dG8gY2FwYWNpdHkgPSBDYXBhY2l0eTsKCQkJc3RhdGljIGNvbnN0IGF1dG8gcmF0ZSA9IDI1ICogd2lkdGggLSBjYXBhY2l0eTsKCgkJCXN0YXRpYyBjb25zdCBhdXRvIGJ5dGVfd2lkdGggPSB3aWR0aCAvIGJ5dGVfYml0czsKCQkJc3RhdGljIGNvbnN0IGF1dG8gYnl0ZV9jYXBhY2l0eSA9IGNhcGFjaXR5IC8gYnl0ZV9iaXRzOwoJCQlzdGF0aWMgY29uc3QgYXV0byBieXRlX3JhdGUgPSByYXRlIC8gYnl0ZV9iaXRzOwoKCQkJc3RhdGljIGNvbnN0IGF1dG8gcm91bmRzID0gMTIgKyAyICogc3RhdGljX2xvZzI8d2lkdGg+Ojp2YWx1ZTsKCgkJCXN0YXRpY19hc3NlcnQod2lkdGggJSBieXRlX2JpdHMgPT0gMCwgIlN1Yi1ieXRlIGhhY2tzIGFyZSBub3Qgc3VwcG9ydGVkLiIpOwoJCQlzdGF0aWNfYXNzZXJ0KGNhcGFjaXR5ICUgYnl0ZV9iaXRzID09IDAsICJTdWItYnl0ZSBoYWNrcyBhcmUgbm90IHN1cHBvcnRlZC4iKTsKCQkJc3RhdGljX2Fzc2VydChyYXRlICUgYnl0ZV9iaXRzID09IDAsICJTdWItYnl0ZSBoYWNrcyBhcmUgbm90IHN1cHBvcnRlZC4iKTsKCgkJCXN0YXRpY19hc3NlcnQocmF0ZSAlIHdpZHRoID09IDAsICJSYXRlIC8gd2lkdGggY29tYmluYXRpb24gaW1wb3NzaWJsZS4iKTsKCQkJc3RhdGljX2Fzc2VydChieXRlX3JhdGUgJSBieXRlX3dpZHRoID09IDAsICJSYXRlIC8gd2lkdGggY29tYmluYXRpb24gbm90IHN1cHBvcnRlZC4iKTsKCgkJCXN0YXRpY19hc3NlcnQoY2FwYWNpdHkgPCAyNSAqIHdpZHRoLCAiQ2FwYWNpdHkgdG9vIGhpZ2guIik7CgoJCXByaXZhdGU6CgkJCXN0YXRlX3R5cGUgc3RhdGVfOwoKCQlwdWJsaWM6CgkJCWtlY2Nha19zdGF0ZSgpCgkJCQk6IHN0YXRlXygpCgkJCXt9CgoJCQljb25zdCBwbGFuZV90eXBlJiBvcGVyYXRvciBbXSAoc3RkOjpzaXplX3QgaSkgY29uc3QKCQkJewoJCQkJcmV0dXJuIHN0YXRlX1tpXTsKCQkJfQoKCQkJcGxhbmVfdHlwZSYgb3BlcmF0b3IgW10gKHN0ZDo6c2l6ZV90IGkpCgkJCXsKCQkJCXJldHVybiBzdGF0ZV9baV07CgkJCX0KCgkJCWNvbnN0IGxhbmVfdHlwZSogZGF0YSgpIGNvbnN0CgkJCXsKCQkJCXJldHVybiBzdGF0ZV8uZGF0YSgpWzBdOwoJCQl9CgoJCQlsYW5lX3R5cGUqIGRhdGEoKQoJCQl7CgkJCQlyZXR1cm4gc3RhdGVfLmRhdGEoKVswXTsKCQkJfQoKCQkJdm9pZCB0cmFuc2Zvcm0oKQoJCQl7CgkJCQlrZWNjYWtfZjxyb3VuZHM+KHN0YXRlXyk7CgkJCX0KCQl9OwoKCQl0ZW1wbGF0ZSA8dHlwZW5hbWUgU3RhdGVUeXBlPgoJCWNsYXNzIHNwb25nZV9hYnNvcmJlcgoJCXsKCQlwdWJsaWM6CgkJCXR5cGVkZWYgU3RhdGVUeXBlIHN0YXRlX3R5cGU7CgkJCXR5cGVkZWYgdHlwZW5hbWUgc3RhdGVfdHlwZTo6bGFuZV90eXBlIGxhbmVfdHlwZTsKCgkJcHJpdmF0ZToKCQkJc3RhdGVfdHlwZSBzdGF0ZV87CgkJCXN0ZDo6c2l6ZV90IGJ5dGVzX2Fic29yYmVkXzsKCgkJcHVibGljOgoJCQlzcG9uZ2VfYWJzb3JiZXIoKQoJCQkJOiBieXRlc19hYnNvcmJlZF8oKQoJCQl7fQoKCQkJc3BvbmdlX2Fic29yYmVyKGNvbnN0IHZvaWQqIGRhdGEsIHN0ZDo6c2l6ZV90IHNpemUpCgkJCQk6IGJ5dGVzX2Fic29yYmVkXygpCgkJCXsKCQkJCSgqdGhpcykoZGF0YSwgc2l6ZSk7CgkJCX0KCgkJCXZvaWQgb3BlcmF0b3IgKCkgKGNvbnN0IHZvaWQqIGRhdGEsIHN0ZDo6c2l6ZV90IHNpemUpCgkJCXsKCQkJCWF1dG8gZGF0YV9ieXRlcyA9IHN0YXRpY19jYXN0PGNvbnN0IHN0ZDo6dWludDhfdCo+KGRhdGEpOwoKCQkJCXdoaWxlIChzaXplICE9IDApCgkJCQl7CgkJCQkJd2hpbGUgKGJ5dGVzX2Fic29yYmVkXyA9PSAwICYmIHNpemUgPj0gc3RhdGVfdHlwZTo6Ynl0ZV9yYXRlKQoJCQkJCXsKCQkJCQkJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSAhPSBzdGF0ZV90eXBlOjpieXRlX3JhdGUgLyBzdGF0ZV90eXBlOjpieXRlX3dpZHRoOyArK2kpCgkJCQkJCXsKCQkJCQkJCWxhbmVfdHlwZSBsYW5lOwoJCQkJCQkJc3RkOjptZW1jcHkoJmxhbmUsIGRhdGFfYnl0ZXMgKyBpICogc3RhdGVfdHlwZTo6Ynl0ZV93aWR0aCwgc3RhdGVfdHlwZTo6Ynl0ZV93aWR0aCk7CgkJCQkJCQkqKHN0YXRlX1swXSArIGkpIF49IGxhbmU7CgkJCQkJCX0KCgkJCQkJCWRhdGFfYnl0ZXMgKz0gc3RhdGVfdHlwZTo6Ynl0ZV9yYXRlOwoJCQkJCQlzaXplIC09IHN0YXRlX3R5cGU6OmJ5dGVfcmF0ZTsKCgkJCQkJCXN0YXRlXy50cmFuc2Zvcm0oKTsKCQkJCQl9CgoJCQkJCWlmIChzaXplICE9IDApCgkJCQkJewoJCQkJCQlyZWludGVycHJldF9jYXN0PHN0ZDo6dWludDhfdCo+KHN0YXRlXy5kYXRhKCkpW2J5dGVzX2Fic29yYmVkX10gXj0gKmRhdGFfYnl0ZXM7CgoJCQkJCQkrK2RhdGFfYnl0ZXM7CgkJCQkJCS0tc2l6ZTsKCgkJCQkJCWlmICgrK2J5dGVzX2Fic29yYmVkXyA9PSBzdGF0ZV90eXBlOjpieXRlX3JhdGUpCgkJCQkJCXsKCQkJCQkJCXN0YXRlXy50cmFuc2Zvcm0oKTsKCQkJCQkJCWJ5dGVzX2Fic29yYmVkXyA9IDA7CgkJCQkJCX0KCQkJCQl9CgkJCQl9CgkJCX0KCgkJCXN0ZDo6c2l6ZV90IGJ5dGVzX2Fic29yYmVkKCkgY29uc3QKCQkJewoJCQkJcmV0dXJuIGJ5dGVzX2Fic29yYmVkXzsKCQkJfQoKCQkJY29uc3Qgc3RhdGVfdHlwZSYgaW50ZXJuYWxfc3RhdGUoKSBjb25zdAoJCQl7CgkJCQlyZXR1cm4gc3RhdGVfOwoJCQl9CgoJCQlzdGF0ZV90eXBlJiBpbnRlcm5hbF9zdGF0ZSgpCgkJCXsKCQkJCXJldHVybiBzdGF0ZV87CgkJCX0KCQl9OwoKCQl0ZW1wbGF0ZSA8dHlwZW5hbWUgU3RhdGVUeXBlPgoJCWNsYXNzIHNwb25nZV9zcXVlZXplcgoJCXsKCQlwdWJsaWM6CgkJCXR5cGVkZWYgU3RhdGVUeXBlIHN0YXRlX3R5cGU7CgkJCXR5cGVkZWYgdHlwZW5hbWUgc3RhdGVfdHlwZTo6bGFuZV90eXBlIGxhbmVfdHlwZTsKCgkJcHJpdmF0ZToKCQkJc3RhdGVfdHlwZSBzdGF0ZV87CgkJCXN0ZDo6c2l6ZV90IGJ5dGVzX3NxdWVlemVkXzsKCgkJcHVibGljOgoJCQlzcG9uZ2Vfc3F1ZWV6ZXIoc3BvbmdlX2Fic29yYmVyPHN0YXRlX3R5cGU+IGFic29yYmVyKQoJCQkJOiBzdGF0ZV8oYWJzb3JiZXIuaW50ZXJuYWxfc3RhdGUoKSkKCQkJCSwgYnl0ZXNfc3F1ZWV6ZWRfKCkKCQkJewoJCQkJcmVpbnRlcnByZXRfY2FzdDxzdGQ6OnVpbnQ4X3QqPihzdGF0ZV8uZGF0YSgpKVthYnNvcmJlci5ieXRlc19hYnNvcmJlZCgpXSBePSAxdTsKCQkJCXJlaW50ZXJwcmV0X2Nhc3Q8c3RkOjp1aW50OF90Kj4oc3RhdGVfLmRhdGEoKSlbc3RhdGVfdHlwZTo6Ynl0ZV9yYXRlIC0gMV0gXj0gMTI4dTsKCQkJCXN0YXRlXy50cmFuc2Zvcm0oKTsKCQkJfQoKCQkJdm9pZCBvcGVyYXRvciAoKSAodm9pZCogYnVmLCBzdGQ6OnNpemVfdCBzaXplKQoJCQl7CgkJCQlhdXRvIGJ1Zl9ieXRlcyA9IHN0YXRpY19jYXN0PHN0ZDo6dWludDhfdCo+KGJ1Zik7CgoJCQkJd2hpbGUgKHNpemUgIT0gMCkKCQkJCXsKCQkJCQl3aGlsZSAoYnl0ZXNfc3F1ZWV6ZWRfID09IDAgJiYgc2l6ZSA+PSBzdGF0ZV90eXBlOjpieXRlX3JhdGUpCgkJCQkJewoJCQkJCQlzdGQ6Om1lbWNweShidWZfYnl0ZXMsIHN0YXRlXy5kYXRhKCksIHN0YXRlX3R5cGU6OmJ5dGVfcmF0ZSk7CgoJCQkJCQlidWZfYnl0ZXMgKz0gc3RhdGVfdHlwZTo6Ynl0ZV9yYXRlOwoJCQkJCQlzaXplIC09IHN0YXRlX3R5cGU6OmJ5dGVfcmF0ZTsKCgkJCQkJCXN0YXRlXy50cmFuc2Zvcm0oKTsKCQkJCQl9CgoJCQkJCWlmIChzaXplICE9IDApCgkJCQkJewoJCQkJCQljb25zdCBhdXRvIGNvcHlfc2l6ZSA9IHN0ZDo6bWluKHNpemUsIHN0YXRlX3R5cGU6OmJ5dGVfcmF0ZSAtIGJ5dGVzX3NxdWVlemVkXyk7CgkJCQkJCWNvbnN0IGF1dG8gc3RhdGVfYnl0ZXMgPSByZWludGVycHJldF9jYXN0PHN0ZDo6dWludDhfdCo+KHN0YXRlXy5kYXRhKCkpOwoKCQkJCQkJc3RkOjptZW1jcHkoYnVmX2J5dGVzLCBzdGF0ZV9ieXRlcyArIGJ5dGVzX3NxdWVlemVkXywgY29weV9zaXplKTsKCgkJCQkJCWJ1Zl9ieXRlcyArPSBjb3B5X3NpemU7CgkJCQkJCXNpemUgLT0gY29weV9zaXplOwoJCQkJCQlieXRlc19zcXVlZXplZF8gKz0gY29weV9zaXplOwoKCQkJCQkJaWYgKGJ5dGVzX3NxdWVlemVkXyA9PSBzdGF0ZV90eXBlOjpieXRlX3JhdGUpCgkJCQkJCXsKCQkJCQkJCXN0YXRlXy50cmFuc2Zvcm0oKTsKCQkJCQkJCWJ5dGVzX3NxdWVlemVkXyA9IDA7CgkJCQkJCX0KCQkJCQl9CgkJCQl9CgkJCX0KCgkJCXN0ZDo6c2l6ZV90IGJ5dGVzX3NxdWVlemVkKCkgY29uc3QKCQkJewoJCQkJcmV0dXJuIGJ5dGVzX3NxdWVlemVkXzsKCQkJfQoKCQkJY29uc3Qgc3RhdGVfdHlwZSYgaW50ZXJuYWxfc3RhdGUoKSBjb25zdAoJCQl7CgkJCQlyZXR1cm4gc3RhdGVfOwoJCQl9CgoJCQlzdGF0ZV90eXBlJiBpbnRlcm5hbF9zdGF0ZSgpCgkJCXsKCQkJCXJldHVybiBzdGF0ZV87CgkJCX0KCQl9OwoKCQljb25zdCBzdGQ6OnVpbnQ2NF90IHJvdW5kX2NvbnN0YW50c1syNF0gPQoJCXsKCQkJMHgwMDAwMDAwMDAwMDAwMDAxdWxsLAoJCQkweDAwMDAwMDAwMDAwMDgwODJ1bGwsCgkJCTB4ODAwMDAwMDAwMDAwODA4QXVsbCwKCQkJMHg4MDAwMDAwMDgwMDA4MDAwdWxsLAoJCQkweDAwMDAwMDAwMDAwMDgwOEJ1bGwsCgkJCTB4MDAwMDAwMDA4MDAwMDAwMXVsbCwKCQkJMHg4MDAwMDAwMDgwMDA4MDgxdWxsLAoJCQkweDgwMDAwMDAwMDAwMDgwMDl1bGwsCgkJCTB4MDAwMDAwMDAwMDAwMDA4QXVsbCwKCQkJMHgwMDAwMDAwMDAwMDAwMDg4dWxsLAoJCQkweDAwMDAwMDAwODAwMDgwMDl1bGwsCgkJCTB4MDAwMDAwMDA4MDAwMDAwQXVsbCwKCQkJMHgwMDAwMDAwMDgwMDA4MDhCdWxsLAoJCQkweDgwMDAwMDAwMDAwMDAwOEJ1bGwsCgkJCTB4ODAwMDAwMDAwMDAwODA4OXVsbCwKCQkJMHg4MDAwMDAwMDAwMDA4MDAzdWxsLAoJCQkweDgwMDAwMDAwMDAwMDgwMDJ1bGwsCgkJCTB4ODAwMDAwMDAwMDAwMDA4MHVsbCwKCQkJMHgwMDAwMDAwMDAwMDA4MDBBdWxsLAoJCQkweDgwMDAwMDAwODAwMDAwMEF1bGwsCgkJCTB4ODAwMDAwMDA4MDAwODA4MXVsbCwKCQkJMHg4MDAwMDAwMDAwMDA4MDgwdWxsLAoJCQkweDAwMDAwMDAwODAwMDAwMDF1bGwsCgkJCTB4ODAwMDAwMDA4MDAwODAwOHVsbCwKCQl9OwoKCQl0ZW1wbGF0ZSA8dW5zaWduZWQgUm91bmRzLCB0eXBlbmFtZSBTdGF0ZVR5cGU+CgkJdm9pZCBrZWNjYWtfZihTdGF0ZVR5cGUmIHN0YXRlKQoJCXsKCQkJZm9yICh1bnNpZ25lZCBpID0gMDsgaSAhPSBSb3VuZHM7ICsraSkKCQkJewoJCQkJcm91bmQoc3RhdGUsIHJvdW5kX2NvbnN0YW50c1tpXSk7CgkJCX0KCQl9CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBOLCB0eXBlbmFtZSBXb3JkPgoJCVdvcmQgc2hsKFdvcmQgdykKCQl7CgkJCXJldHVybiB3IDw8IChOKTsKCQl9CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBOLCB0eXBlbmFtZSBXb3JkPgoJCVdvcmQgc2hyKFdvcmQgdykKCQl7CgkJCXJldHVybiB3ID4+IChOKTsKCQl9CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBOLCB0eXBlbmFtZSBXb3JkPgoJCVdvcmQgcm90cihXb3JkIHcpCgkJewoJCQlyZXR1cm4gc2hyPE4+KHcpIHwgc2hsPHNpemVvZihXb3JkKSAqIDggLSBOPih3KTsKCQl9CgoJCXRlbXBsYXRlIDx1bnNpZ25lZCBOLCB0eXBlbmFtZSBXb3JkPgoJCVdvcmQgcm90bChXb3JkIHcpCgkJewoJCQlyZXR1cm4gc2hsPE4+KHcpIHwgc2hyPHNpemVvZihXb3JkKSAqIDggLSBOPih3KTsKCQl9CgoJCXRlbXBsYXRlIDx0eXBlbmFtZSBXb3JkPgoJCVdvcmQgcm90cihXb3JkIHcsIHVuc2lnbmVkIG4pCgkJewoJCQlyZXR1cm4gKHcgPj4gbikgfCAodyA8PCAoc2l6ZW9mKFdvcmQpICogOCAtIG4pKTsKCQl9CgoJCXRlbXBsYXRlIDx0eXBlbmFtZSBXb3JkPgoJCVdvcmQgcm90bChXb3JkIHcsIHVuc2lnbmVkIG4pCgkJewoJCQlyZXR1cm4gKHcgPDwgbikgfCAodyA+PiAoc2l6ZW9mKFdvcmQpICogOCAtIG4pKTsKCQl9CgoJCXR5cGVkZWYgdW5zaWduZWQgcm90YXRpb25fb2Zmc2V0X3R5cGU7CgoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMF8wID0gMDsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzBfMSA9IDM2OwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMF8yID0gMzsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzBfMyA9IDQxOwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMF80ID0gMTg7CgoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMV8wID0gMTsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzFfMSA9IDQ0OwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMV8yID0gMTA7CgkJY29uc3Qgcm90YXRpb25fb2Zmc2V0X3R5cGUgcm9mZnNldF8xXzMgPSA0NTsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzFfNCA9IDI7CgoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMl8wID0gNjI7CgkJY29uc3Qgcm90YXRpb25fb2Zmc2V0X3R5cGUgcm9mZnNldF8yXzEgPSA2OwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfMl8yID0gNDM7CgkJY29uc3Qgcm90YXRpb25fb2Zmc2V0X3R5cGUgcm9mZnNldF8yXzMgPSAxNTsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzJfNCA9IDYxOwoKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzNfMCA9IDI4OwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfM18xID0gNTU7CgkJY29uc3Qgcm90YXRpb25fb2Zmc2V0X3R5cGUgcm9mZnNldF8zXzIgPSAyNTsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzNfMyA9IDIxOwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfM180ID0gNTY7CgoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfNF8wID0gMjc7CgkJY29uc3Qgcm90YXRpb25fb2Zmc2V0X3R5cGUgcm9mZnNldF80XzEgPSAyMDsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzRfMiA9IDM5OwoJCWNvbnN0IHJvdGF0aW9uX29mZnNldF90eXBlIHJvZmZzZXRfNF8zID0gODsKCQljb25zdCByb3RhdGlvbl9vZmZzZXRfdHlwZSByb2Zmc2V0XzRfNCA9IDE0OwoKCQl0ZW1wbGF0ZSA8dHlwZW5hbWUgU3RhdGVUeXBlLCB0eXBlbmFtZSBMYW5lVHlwZT4KCQl2b2lkIHJvdW5kKFN0YXRlVHlwZSYgcywgTGFuZVR5cGUgcm91bmRfY29uc3RhbnQpCgkJewoJCQlhdXRvIGMwID0gc1swXVswXSBeIHNbMV1bMF0gXiBzWzJdWzBdIF4gc1szXVswXSBeIHNbNF1bMF07CgkJCWF1dG8gYzEgPSBzWzBdWzFdIF4gc1sxXVsxXSBeIHNbMl1bMV0gXiBzWzNdWzFdIF4gc1s0XVsxXTsKCQkJYXV0byBjMiA9IHNbMF1bMl0gXiBzWzFdWzJdIF4gc1syXVsyXSBeIHNbM11bMl0gXiBzWzRdWzJdOwoJCQlhdXRvIGMzID0gc1swXVszXSBeIHNbMV1bM10gXiBzWzJdWzNdIF4gc1szXVszXSBeIHNbNF1bM107CgkJCWF1dG8gYzQgPSBzWzBdWzRdIF4gc1sxXVs0XSBeIHNbMl1bNF0gXiBzWzNdWzRdIF4gc1s0XVs0XTsKCgkJCWF1dG8gZDAgPSBjNCBeIHJvdGw8MT4oYzEpOwoJCQlhdXRvIGQxID0gYzAgXiByb3RsPDE+KGMyKTsKCQkJYXV0byBkMiA9IGMxIF4gcm90bDwxPihjMyk7CgkJCWF1dG8gZDMgPSBjMiBeIHJvdGw8MT4oYzQpOwoJCQlhdXRvIGQ0ID0gYzMgXiByb3RsPDE+KGMwKTsKCgkJCXNbMF1bMF0gXj0gZDA7CgkJCXNbMF1bMV0gXj0gZDE7CgkJCXNbMF1bMl0gXj0gZDI7CgkJCXNbMF1bM10gXj0gZDM7CgoJCQlhdXRvIHMwMCA9IChzWzBdWzBdKTsgLyogcm90bDxyb2Zmc2V0XzBfMD4gKi8KCQkJYXV0byBzMjAgPSByb3RsPHJvZmZzZXRfMV8wPihzWzBdWzFdKTsKCQkJYXV0byBzNDAgPSByb3RsPHJvZmZzZXRfMl8wPihzWzBdWzJdKTsKCQkJYXV0byBzMTAgPSByb3RsPHJvZmZzZXRfM18wPihzWzBdWzNdKTsKCgkJCXNbMF1bNF0gXj0gZDQ7CgkJCXNbMV1bMF0gXj0gZDA7CgkJCXNbMV1bMV0gXj0gZDE7CgkJCXNbMV1bMl0gXj0gZDI7CgoJCQlhdXRvIHMzMCA9IHJvdGw8cm9mZnNldF80XzA+KHNbMF1bNF0pOwoJCQlhdXRvIHMzMSA9IHJvdGw8cm9mZnNldF8wXzE+KHNbMV1bMF0pOwoJCQlhdXRvIHMwMSA9IHJvdGw8cm9mZnNldF8xXzE+KHNbMV1bMV0pOwoJCQlhdXRvIHMyMSA9IHJvdGw8cm9mZnNldF8yXzE+KHNbMV1bMl0pOwoKCQkJc1sxXVszXSBePSBkMzsKCQkJc1sxXVs0XSBePSBkNDsKCQkJc1syXVswXSBePSBkMDsKCQkJc1syXVsxXSBePSBkMTsKCgkJCWF1dG8gczQxID0gcm90bDxyb2Zmc2V0XzNfMT4oc1sxXVszXSk7CgkJCWF1dG8gczExID0gcm90bDxyb2Zmc2V0XzRfMT4oc1sxXVs0XSk7CgkJCWF1dG8gczEyID0gcm90bDxyb2Zmc2V0XzBfMj4oc1syXVswXSk7CgkJCWF1dG8gczMyID0gcm90bDxyb2Zmc2V0XzFfMj4oc1syXVsxXSk7CgoJCQlzWzJdWzJdIF49IGQyOwoJCQlzWzJdWzNdIF49IGQzOwoJCQlzWzJdWzRdIF49IGQ0OwoJCQlzWzNdWzBdIF49IGQwOwoKCQkJYXV0byBzMDIgPSByb3RsPHJvZmZzZXRfMl8yPihzWzJdWzJdKTsKCQkJYXV0byBzMjIgPSByb3RsPHJvZmZzZXRfM18yPihzWzJdWzNdKTsKCQkJYXV0byBzNDIgPSByb3RsPHJvZmZzZXRfNF8yPihzWzJdWzRdKTsKCQkJYXV0byBzNDMgPSByb3RsPHJvZmZzZXRfMF8zPihzWzNdWzBdKTsKCgkJCXNbM11bMV0gXj0gZDE7CgkJCXNbM11bMl0gXj0gZDI7CgkJCXNbM11bM10gXj0gZDM7CgkJCXNbM11bNF0gXj0gZDQ7CgoJCQlhdXRvIHMxMyA9IHJvdGw8cm9mZnNldF8xXzM+KHNbM11bMV0pOwoJCQlhdXRvIHMzMyA9IHJvdGw8cm9mZnNldF8yXzM+KHNbM11bMl0pOwoJCQlhdXRvIHMwMyA9IHJvdGw8cm9mZnNldF8zXzM+KHNbM11bM10pOwoJCQlhdXRvIHMyMyA9IHJvdGw8cm9mZnNldF80XzM+KHNbM11bNF0pOwoKCQkJc1s0XVswXSBePSBkMDsKCQkJc1s0XVsxXSBePSBkMTsKCQkJc1s0XVsyXSBePSBkMjsKCQkJc1s0XVszXSBePSBkMzsKCgkJCWF1dG8gczI0ID0gcm90bDxyb2Zmc2V0XzBfND4oc1s0XVswXSk7CgkJCWF1dG8gczQ0ID0gcm90bDxyb2Zmc2V0XzFfND4oc1s0XVsxXSk7CgkJCWF1dG8gczE0ID0gcm90bDxyb2Zmc2V0XzJfND4oc1s0XVsyXSk7CgkJCWF1dG8gczM0ID0gcm90bDxyb2Zmc2V0XzNfND4oc1s0XVszXSk7CgoJCQlzWzRdWzRdIF49IGQ0OwoJCQlhdXRvIHMwNCA9IHJvdGw8cm9mZnNldF80XzQ+KHNbNF1bNF0pOwoKCQkJLy8gCgkJCXNbMF1bMF0gPSBzMDAgXiAofnMwMSAmIHMwMik7CgkJCXNbMF1bMV0gPSBzMDEgXiAofnMwMiAmIHMwMyk7CgkJCXNbMF1bMl0gPSBzMDIgXiAofnMwMyAmIHMwNCk7CgkJCXNbMF1bM10gPSBzMDMgXiAofnMwNCAmIHMwMCk7CgkJCXNbMF1bNF0gPSBzMDQgXiAofnMwMCAmIHMwMSk7CgoJCQlzWzFdWzBdID0gczEwIF4gKH5zMTEgJiBzMTIpOwoJCQlzWzFdWzFdID0gczExIF4gKH5zMTIgJiBzMTMpOwoJCQlzWzFdWzJdID0gczEyIF4gKH5zMTMgJiBzMTQpOwoJCQlzWzFdWzNdID0gczEzIF4gKH5zMTQgJiBzMTApOwoJCQlzWzFdWzRdID0gczE0IF4gKH5zMTAgJiBzMTEpOwoKCQkJc1syXVswXSA9IHMyMCBeICh+czIxICYgczIyKTsKCQkJc1syXVsxXSA9IHMyMSBeICh+czIyICYgczIzKTsKCQkJc1syXVsyXSA9IHMyMiBeICh+czIzICYgczI0KTsKCQkJc1syXVszXSA9IHMyMyBeICh+czI0ICYgczIwKTsKCQkJc1syXVs0XSA9IHMyNCBeICh+czIwICYgczIxKTsKCgkJCXNbM11bMF0gPSBzMzAgXiAofnMzMSAmIHMzMik7CgkJCXNbM11bMV0gPSBzMzEgXiAofnMzMiAmIHMzMyk7CgkJCXNbM11bMl0gPSBzMzIgXiAofnMzMyAmIHMzNCk7CgkJCXNbM11bM10gPSBzMzMgXiAofnMzNCAmIHMzMCk7CgkJCXNbM11bNF0gPSBzMzQgXiAofnMzMCAmIHMzMSk7CgoJCQlzWzRdWzBdID0gczQwIF4gKH5zNDEgJiBzNDIpOwoJCQlzWzRdWzFdID0gczQxIF4gKH5zNDIgJiBzNDMpOwoJCQlzWzRdWzJdID0gczQyIF4gKH5zNDMgJiBzNDQpOwoJCQlzWzRdWzNdID0gczQzIF4gKH5zNDQgJiBzNDApOwoJCQlzWzRdWzRdID0gczQ0IF4gKH5zNDAgJiBzNDEpOwoKCQkJc1swXVswXSBePSByb3VuZF9jb25zdGFudDsKCQl9Cgl9Cn0KCiNlbmRpZgoKCgoKI2lmbmRlZiBLRUNDQUtfSFBQCiNkZWZpbmUgS0VDQ0FLX0hQUAoKI2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8Y3N0ZGludD4KI2luY2x1ZGUgPGxpbWl0cz4KCi8vI2luY2x1ZGUgImtlY2Nha19kZXRhaWwuaHBwIgoKbmFtZXNwYWNlIGtlY2Nhawp7Cgl0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgQ29sbGlzaW9uUmVzaXN0YW5jZSwgc3RkOjpzaXplX3QgUHJlaW1hZ2VSZXNpc3RhbmNlPgoJY2xhc3MgYmFzaWNfaGFzaGVyCgl7CglwdWJsaWM6CgkJc3RhdGljIGNvbnN0IGF1dG8gY29sbGlzaW9uX3Jlc2lzdGFuY2UgPSBDb2xsaXNpb25SZXNpc3RhbmNlOwoJCXN0YXRpYyBjb25zdCBhdXRvIHByZWltYWdlX3Jlc2lzdGFuY2UgPSBQcmVpbWFnZVJlc2lzdGFuY2U7CgoJCXN0YXRpYyBjb25zdCBhdXRvIGNhcGFjaXR5ID0gZGV0YWlsOjpzdGF0aWNfbWF4PGNvbGxpc2lvbl9yZXNpc3RhbmNlICogMiwgcHJlaW1hZ2VfcmVzaXN0YW5jZSAqIDI+Ojp2YWx1ZTsKCQlzdGF0aWMgY29uc3QgYXV0byBoYXNoX3NpemUgPSBkZXRhaWw6OnN0YXRpY19tYXg8Y29sbGlzaW9uX3Jlc2lzdGFuY2UgKiAyIC8gOCwgcHJlaW1hZ2VfcmVzaXN0YW5jZSAvIDg+Ojp2YWx1ZTsKCgkJdHlwZWRlZiBkZXRhaWw6OmtlY2Nha19zdGF0ZTxzdGQ6OnVpbnQ2NF90LCBjYXBhY2l0eT4gc3RhdGVfdHlwZTsKCgkJdHlwZWRlZiBzdGQ6OmFycmF5PHN0ZDo6dWludDhfdCwgaGFzaF9zaXplPiBoYXNoX3R5cGU7CQkKCglwcml2YXRlOgoJCWRldGFpbDo6c3BvbmdlX2Fic29yYmVyPHN0YXRlX3R5cGU+IGFic29yYl87CgoJcHVibGljOgoJCXZvaWQgdXBkYXRlKGNvbnN0IHZvaWQqIGRhdGEsIHN0ZDo6c2l6ZV90IHNpemUpCgkJewoJCQlhYnNvcmJfKGRhdGEsIHNpemUpOwoJCX0KCgkJdm9pZCBmaW5pc2godm9pZCogYnVmLCBzdGQ6OnNpemVfdCBzaXplKQoJCXsKCQkJZGV0YWlsOjpzcG9uZ2Vfc3F1ZWV6ZXI8c3RhdGVfdHlwZT4gc3F1ZWV6ZShzdGQ6Om1vdmUoYWJzb3JiXykpOwoJCQlzcXVlZXplKGJ1Ziwgc2l6ZSk7CgkJCSp0aGlzID0gYmFzaWNfaGFzaGVyKCk7CgkJfQoKCQloYXNoX3R5cGUgZmluaXNoKCkKCQl7CgkJCWhhc2hfdHlwZSBoYXNoOwoJCQlmaW5pc2goaGFzaC5kYXRhKCksIGhhc2guc2l6ZSgpKTsKCQkJcmV0dXJuIGhhc2g7CgkJfQoJfTsKCgl0eXBlZGVmIGJhc2ljX2hhc2hlcjwxMTIsIDIyND4gc2hhM18yNDRfaGFzaGVyOwoJdHlwZWRlZiBiYXNpY19oYXNoZXI8MTI4LCAyNTY+IHNoYTNfMjU2X2hhc2hlcjsKCXR5cGVkZWYgYmFzaWNfaGFzaGVyPDE5MiwgMzg0PiBzaGEzXzM4NF9oYXNoZXI7Cgl0eXBlZGVmIGJhc2ljX2hhc2hlcjwyNTYsIDUxMj4gc2hhM181MTJfaGFzaGVyOwoKCXR5cGVkZWYgYmFzaWNfaGFzaGVyPDExMiwgMTEyPiBzMTEyX2hhc2hlcjsKCXR5cGVkZWYgYmFzaWNfaGFzaGVyPDEyOCwgMTI4PiBzMTI4X2hhc2hlcjsKCXR5cGVkZWYgYmFzaWNfaGFzaGVyPDE5MiwgMTkyPiBzMTkyX2hhc2hlcjsKCXR5cGVkZWYgYmFzaWNfaGFzaGVyPDI1NiwgMjU2PiBzMjU2X2hhc2hlcjsKCgl0ZW1wbGF0ZSA8c3RkOjpzaXplX3QgU2VjdXJpdHlTdHJlbmd0aD4KCWNsYXNzIGJhc2ljX3N0cmVhbV9jcnlwdGVyCgl7CglwdWJsaWM6CgkJc3RhdGljIGNvbnN0IGF1dG8gc2VjdXJpdHlfc3RyZW5ndGggPSBTZWN1cml0eVN0cmVuZ3RoOwoKCQl0eXBlZGVmIGRldGFpbDo6a2VjY2FrX3N0YXRlPHN0ZDo6dWludDY0X3QsIHNlY3VyaXR5X3N0cmVuZ3RoICogMj4gc3RhdGVfdHlwZTsKCQl0eXBlZGVmIHR5cGVuYW1lIHN0YXRlX3R5cGU6OmxhbmVfdHlwZSBsYW5lX3R5cGU7CgoJcHJpdmF0ZToKCQlkZXRhaWw6OnNwb25nZV9zcXVlZXplcjxzdGF0ZV90eXBlPiBzcXVlZXplXzsKCglwdWJsaWM6CgkJYmFzaWNfc3RyZWFtX2NyeXB0ZXIoY29uc3Qgdm9pZCoga2V5LCBzdGQ6OnNpemVfdCBrZXlsZW4pCgkJCTogc3F1ZWV6ZV8oZGV0YWlsOjpzcG9uZ2VfYWJzb3JiZXI8c3RhdGVfdHlwZT4oa2V5LCBrZXlsZW4pKQoJCXt9CgoJCXZvaWQgb3BlcmF0b3IgKCkgKHZvaWQqIGJ1ZiwgY29uc3Qgdm9pZCogZGF0YSwgc3RkOjpzaXplX3Qgc2l6ZSkKCQl7CgkJCWF1dG8gZHB0ciA9IHN0YXRpY19jYXN0PGNvbnN0IHN0ZDo6dWludDhfdCo+KGRhdGEpOwoJCQlhdXRvIGJwdHIgPSBzdGF0aWNfY2FzdDxzdGQ6OnVpbnQ4X3QqPihidWYpOwoJCQlhdXRvIG1zaXplID0gc2l6ZSAvIHNpemVvZihsYW5lX3R5cGUpOwoJCQlhdXRvIHJzaXplID0gc2l6ZSAlIHNpemVvZihsYW5lX3R5cGUpOwoKCQkJYXV0byBzaGlmdCA9IGFwcGx5PGxhbmVfdHlwZT4oYnB0ciwgZHB0ciwgbXNpemUpOwoJCQlhcHBseTxzdGQ6OnVpbnQ4X3Q+KGJwdHIgKyBzaGlmdCwgZHB0ciArIHNoaWZ0LCByc2l6ZSk7CgkJfQoKCXByaXZhdGU6CgkJdGVtcGxhdGUgPHR5cGVuYW1lIExhbmVUeXBlPgoJCXN0ZDo6c2l6ZV90IGFwcGx5KHZvaWQqIGJ1ZiwgY29uc3Qgdm9pZCogZGF0YSwgc3RkOjpzaXplX3Qgc2l6ZSkKCQl7CgkJCWF1dG8gZHB0ciA9IHN0YXRpY19jYXN0PGNvbnN0IHN0ZDo6dWludDhfdCo+KGRhdGEpOwoJCQlhdXRvIGJwdHIgPSBzdGF0aWNfY2FzdDxzdGQ6OnVpbnQ4X3QqPihidWYpOwoKCQkJZm9yIChhdXRvIGkgPSAwOyBpICE9IHNpemU7ICsraSkKCQkJewoJCQkJTGFuZVR5cGUgbDEsIGwyOwoKCQkJCXNxdWVlemVfKCZsMSwgc2l6ZW9mIGwxKTsKCQkJCXN0ZDo6bWVtY3B5KCZsMiwgZHB0ciArIGkgKiBzaXplb2YoTGFuZVR5cGUpLCBzaXplb2YgbDIpOwoKCQkJCWwxIF49IGwyOwoKCQkJCXN0ZDo6bWVtY3B5KGJwdHIgKyBpICogc2l6ZW9mKExhbmVUeXBlKSwgJmwxLCBzaXplb2YgbDEpOwoJCQl9CgoJCQlyZXR1cm4gc2l6ZSAqIHNpemVvZihMYW5lVHlwZSk7CgkJfQoJfTsKfQoKI2VuZGlmCgoKCgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDxzdHJpbmc+CiAKdm9pZCBkdW1wKGNvbnN0IHZvaWQqIG1lbW9yeSwgc3RkOjpzaXplX3Qgc2l6ZSkKewoJc3RhdGljIGNvbnN0IGNoYXIgdGFibGVbMjU2XVszXSA9IAoJewoJCSIwMCIsICIwMSIsICIwMiIsICIwMyIsICIwNCIsICIwNSIsICIwNiIsICIwNyIsIAoJCSIwOCIsICIwOSIsICIwYSIsICIwYiIsICIwYyIsICIwZCIsICIwZSIsICIwZiIsIAoJCSIxMCIsICIxMSIsICIxMiIsICIxMyIsICIxNCIsICIxNSIsICIxNiIsICIxNyIsIAoJCSIxOCIsICIxOSIsICIxYSIsICIxYiIsICIxYyIsICIxZCIsICIxZSIsICIxZiIsIAoJCSIyMCIsICIyMSIsICIyMiIsICIyMyIsICIyNCIsICIyNSIsICIyNiIsICIyNyIsIAoJCSIyOCIsICIyOSIsICIyYSIsICIyYiIsICIyYyIsICIyZCIsICIyZSIsICIyZiIsIAoJCSIzMCIsICIzMSIsICIzMiIsICIzMyIsICIzNCIsICIzNSIsICIzNiIsICIzNyIsIAoJCSIzOCIsICIzOSIsICIzYSIsICIzYiIsICIzYyIsICIzZCIsICIzZSIsICIzZiIsIAoJCSI0MCIsICI0MSIsICI0MiIsICI0MyIsICI0NCIsICI0NSIsICI0NiIsICI0NyIsIAoJCSI0OCIsICI0OSIsICI0YSIsICI0YiIsICI0YyIsICI0ZCIsICI0ZSIsICI0ZiIsIAoJCSI1MCIsICI1MSIsICI1MiIsICI1MyIsICI1NCIsICI1NSIsICI1NiIsICI1NyIsIAoJCSI1OCIsICI1OSIsICI1YSIsICI1YiIsICI1YyIsICI1ZCIsICI1ZSIsICI1ZiIsIAoJCSI2MCIsICI2MSIsICI2MiIsICI2MyIsICI2NCIsICI2NSIsICI2NiIsICI2NyIsIAoJCSI2OCIsICI2OSIsICI2YSIsICI2YiIsICI2YyIsICI2ZCIsICI2ZSIsICI2ZiIsIAoJCSI3MCIsICI3MSIsICI3MiIsICI3MyIsICI3NCIsICI3NSIsICI3NiIsICI3NyIsIAoJCSI3OCIsICI3OSIsICI3YSIsICI3YiIsICI3YyIsICI3ZCIsICI3ZSIsICI3ZiIsIAoJCSI4MCIsICI4MSIsICI4MiIsICI4MyIsICI4NCIsICI4NSIsICI4NiIsICI4NyIsIAoJCSI4OCIsICI4OSIsICI4YSIsICI4YiIsICI4YyIsICI4ZCIsICI4ZSIsICI4ZiIsIAoJCSI5MCIsICI5MSIsICI5MiIsICI5MyIsICI5NCIsICI5NSIsICI5NiIsICI5NyIsIAoJCSI5OCIsICI5OSIsICI5YSIsICI5YiIsICI5YyIsICI5ZCIsICI5ZSIsICI5ZiIsIAoJCSJhMCIsICJhMSIsICJhMiIsICJhMyIsICJhNCIsICJhNSIsICJhNiIsICJhNyIsIAoJCSJhOCIsICJhOSIsICJhYSIsICJhYiIsICJhYyIsICJhZCIsICJhZSIsICJhZiIsIAoJCSJiMCIsICJiMSIsICJiMiIsICJiMyIsICJiNCIsICJiNSIsICJiNiIsICJiNyIsIAoJCSJiOCIsICJiOSIsICJiYSIsICJiYiIsICJiYyIsICJiZCIsICJiZSIsICJiZiIsIAoJCSJjMCIsICJjMSIsICJjMiIsICJjMyIsICJjNCIsICJjNSIsICJjNiIsICJjNyIsIAoJCSJjOCIsICJjOSIsICJjYSIsICJjYiIsICJjYyIsICJjZCIsICJjZSIsICJjZiIsIAoJCSJkMCIsICJkMSIsICJkMiIsICJkMyIsICJkNCIsICJkNSIsICJkNiIsICJkNyIsIAoJCSJkOCIsICJkOSIsICJkYSIsICJkYiIsICJkYyIsICJkZCIsICJkZSIsICJkZiIsIAoJCSJlMCIsICJlMSIsICJlMiIsICJlMyIsICJlNCIsICJlNSIsICJlNiIsICJlNyIsIAoJCSJlOCIsICJlOSIsICJlYSIsICJlYiIsICJlYyIsICJlZCIsICJlZSIsICJlZiIsIAoJCSJmMCIsICJmMSIsICJmMiIsICJmMyIsICJmNCIsICJmNSIsICJmNiIsICJmNyIsIAoJCSJmOCIsICJmOSIsICJmYSIsICJmYiIsICJmYyIsICJmZCIsICJmZSIsICJmZiIsIAoJfTsKIAoJY29uc3QgdW5zaWduZWQgY2hhciogcCA9IHN0YXRpY19jYXN0PGNvbnN0IHVuc2lnbmVkIGNoYXIqPihtZW1vcnkpOwogCglmb3IgKDsgc2l6ZS0tOyArK3ApCgkJc3RkOjpjb3V0IDw8IHRhYmxlWypwXTsKIAoJc3RkOjpjb3V0IDw8ICdcbic7Cn0KIAppbnQgbWFpbigpCnsKCXN0ZDo6Y291dCA8PCAiS2V5OiAiOwoJc3RkOjpzdHJpbmcga2V5OwoJc3RkOjpnZXRsaW5lKHN0ZDo6Y2luLCBrZXkpOwogCglrZWNjYWs6OmJhc2ljX3N0cmVhbV9jcnlwdGVyPDEyOD4gZW5jcnlwdChrZXkuZGF0YSgpLCBrZXkuc2l6ZSgpKTsKCWtlY2Nhazo6YmFzaWNfc3RyZWFtX2NyeXB0ZXI8MTI4PiBkZWNyeXB0KGtleS5kYXRhKCksIGtleS5zaXplKCkpOwogCglzdGQ6OnN0cmluZyBtc2c7Cgl3aGlsZSAoc3RkOjpjb3V0IDw8ICJNZXNzYWdlOiAiICYmIHN0ZDo6Z2V0bGluZShzdGQ6OmNpbiwgbXNnKSkKCXsKCQlzdGQ6OnN0cmluZyBlbmMobXNnLnNpemUoKSwgJyAnKTsKCQllbmNyeXB0KCZlbmNbMF0sIG1zZy5kYXRhKCksIG1zZy5zaXplKCkpOwoJCXN0ZDo6Y291dCA8PCAiRW5jcnlwdGVkOiAiOwoJCWR1bXAoZW5jLmRhdGEoKSwgZW5jLnNpemUoKSk7CiAKCQlzdGQ6OnN0cmluZyBkZWMobXNnLnNpemUoKSwgJyAnKTsKIAoJCWRlY3J5cHQoJmRlY1swXSwgZW5jLmRhdGEoKSwgZW5jLnNpemUoKSk7CgkJc3RkOjpjb3V0IDw8ICJEZWNyeXB0ZWQ6ICIgPDwgZGVjIDw8ICdcbic7Cgl9Cn0=