#include <iostream>
#include <fstream>
#include <string>
//#include "Tortoise.h"
//#pragma once
#include <vector>
#include <cstdint>
#include <initializer_list>
class Surface32 {
public:
struct Element {
Element() {
this->ui32 = 0xffffffff;
}
Element(std::uint32_t Color) {
this->ui32 = Color;
}
Element(std::uint8_t R, std::uint8_t G, std::uint8_t B) {
this->R = R;
this->G = G;
this->B = B;
this->A = 0xff;
}
Element(std::uint8_t R, std::uint8_t G, std::uint8_t B, std::uint8_t A) {
this->R = R;
this->G = G;
this->B = B;
this->A = A;
}
union {
struct
{
std::uint8_t b, g, r, a;//バイトオーダーが絡むときがあるのでここの並びが大事です!
};
struct
{
std::uint8_t B, G, R, A;//これも!
};
std::uint32_t ui32;
std::uint8_t ui8a[4];
};
};
protected:
typedef std::vector<Element> RowType;
typedef std::vector<RowType> Surface;
public:
Surface32() = delete;
Surface32(std::size_t Width, std::size_t Height) {
Resize(Width, Height);
}
Surface32(std::initializer_list<RowType> i) :S(i.begin(), i.end()) {
H = i.size();
W = (*(i.begin())).size();
Resize(W, H);
}
bool Resize(std::size_t Width, std::size_t Height) {
W = Width;
H = Height;
S.resize(Height);
for (auto&o : S) {
o.resize(Width);
}
return true;
}
bool Fill(const Element& E) {
for (auto&oo : S) {
for (auto&o : oo) {
o = E;
}
}
return true;
}
RowType& operator [](const std::size_t& Idx) {//このインデックスは縦方向を指定しています。
return S[Idx];//返るのは横方向です。
}
Surface::iterator begin() {
return S.begin();
}
Surface::iterator end() {
return S.end();
}
std::size_t Width() {
return W;
}
std::size_t Height() {
return H;
}
bool SetPixel(const std::size_t& X, const std::size_t& Y, const Element& E) {
if (X >= W) return false;
if (Y >= H) return false;
S[Y][X] = E;
return true;
}
protected:
std::size_t W;
std::size_t H;
Surface S;
};
#include <cstdint>
#include <tuple>
#include <cmath>
#include <algorithm>
//#include "Surface32.h"
//read this. http://w...content-available-to-author-only...o.jp/dp/4774136182
//but japanese.
class TortoiseGraphic {
public:
typedef std::tuple <double, double> Vector2D;
public:
TortoiseGraphic() = delete;
TortoiseGraphic(Surface32* Screen) :S(Screen), Angle(), TurnHorizon(false), TurnVertical(true) {}
bool SetPixel(const std::int64_t& X, const std::int64_t& Y, const Surface32::Element& E, bool Tranceform = true) {
if (S == nullptr)return false;
std::int64_t A = X;
std::int64_t B = Y;
if (Tranceform == true) {
double OX, OY;
std::tie(OX, OY) = Origin;
A = static_cast<std::int64_t>(X + OX);
if (TurnHorizon == true) A = S->Width() - A;
B = static_cast<std::int64_t>(Y + OY);
if (TurnVertical == true) B = S->Height() - B;
}
return S->SetPixel(A, B, E);
}
Surface32::Element GetPixel(const std::int64_t& X, const std::int64_t& Y, bool Tranceform = true) {
if (S == nullptr)return false;
std::int64_t A = X;
std::int64_t B = Y;
if (Tranceform == true) {
double OX, OY;
std::tie(OX, OY) = Origin;
A = static_cast<std::int64_t>(X + OX);
if (TurnHorizon == true) A = S->Width() - A;
B = static_cast<std::int64_t>(Y + OY);
if (TurnVertical == true) B = S->Height() - B;
}
//////////////
if (A < 0) return 0x00000000;
if (A >= S->Width()) return 0x00000000;
if (B < 0) return 0x00000000;
if (B >= S->Height()) return 0x00000000;
return (*S)[B][A];
}
bool SetTurnVertical(bool F = true) {
TurnVertical = F;
return true;
}
bool GetTurnVertical() {
return TurnVertical;
}
bool SetTurnHorizon(bool F = false) {
TurnHorizon = F;
return true;
}
bool GetTurnHorizon() {
return TurnHorizon;
}
bool SetAngle(double A) {
Angle = A;
return true;
}
bool Turn(double A) {
Angle += A;
Angle = std::fmod(Angle, 360);
return true;
}
bool SetPoint(double X, double Y) {
Now = std::make_tuple(X, Y);
return true;
}
Vector2D GetPoint() {
return Now;
}
bool SetOrigin(double X, double Y) {
Origin = std::make_tuple(X, Y);
return true;
}
Vector2D GetOrigin() {
return Origin;
}
bool SetColor(const Surface32::Element& Color) {
C = Color;
return true;
}
Surface32::Element GetColor() {
return C;
}
bool Line(std::int64_t x0, std::int64_t y0, std::int64_t x1, std::int64_t y1, bool InDirect = false) {
std::int64_t dx = std::abs(x1 - x0);
std::int64_t dy = std::abs(y1 - y0);
std::int64_t sx, sy;
if (x0 < x1) { sx = 1; }
else { sx = -1; }
if (y0 < y1) { sy = 1; }
else { sy = -1; }
std::int64_t err = dx - dy;
while (true) {
SetPixel(x0, y0, C, !InDirect);
if ((x0 == x1) && (y0 == y1)) break;
std::int64_t e2 = 2 * err;
if (e2 > -dy) {
err = err - dy;
x0 += sx;
}
if (e2 < dx) {
err = err + dx;
y0 += sy;
}
}
return true;
}
bool Move(double L) {
double Nx, Ny;
std::tie(Nx, Ny) = Now;
double X = L * std::cos(Rad*Angle);
double Y = L * std::sin(Rad*Angle);
Line(Nx, Ny, Nx + X, Ny + Y);
SetPoint(Nx + X, Ny + Y);
return true;
}
bool MoveTo(double X, double Y) {
double Nx, Ny;
std::tie(Nx, Ny) = Now;
Line(Nx, Ny, X, Y);
SetPoint(X, Y);
return true;
}
bool Clear() {
if (S == nullptr) return false;
S->Fill(C);
return true;
}
bool ClearUnderFloatingPoint() {
double X, Y;
std::tie(X, Y) = Now;
Now = std::make_tuple(std::floor(X), std::floor(Y));
return true;
}
Surface32* GetSurface() {
return S;
}
protected:
Surface32* S;
double Angle;
Vector2D Now;
Vector2D Origin;
bool TurnVertical;
bool TurnHorizon;
double PI = 3.14159265359;
double Rad = PI / 180.0;
Surface32::Element C;
};
bool WritePPM(std::ostream& os, Surface32& S, std::string comment = "No Comment") {
//write header
os << "P3" << std::endl;
//write comment
os << "#" << comment << std::endl;
//write size
os << S.Width() << ' ' << S.Height() << std::endl;
//bytemax
os << "255" << std::endl;
for (auto& oo : S) {
for (auto& o : oo) {
os << static_cast<std::int16_t>(o.R) << ' ' << static_cast<std::int16_t>(o.G) << ' ' << static_cast<std::int16_t>(o.B) << std::endl;
}
}
return true;
}
bool MakeHoge(TortoiseGraphic& T) {
T.SetOrigin(T.GetSurface()->Width() / 2, T.GetSurface()->Height() / 2);
T.SetTurnVertical();
for (int i = 0; i < 2; i++) {
T.SetColor({ 0,0,0, });
T.SetAngle(0);//輪郭
T.SetPoint(0, -80);
T.Move(96);
T.Turn(60);
T.Move(58);
T.Turn(30);
T.Move(32);
T.Turn(30);
T.Move(58);
T.Turn(30);
T.Move(58);
T.Turn(30);
T.Move(48);
T.SetAngle(0);//輪郭
T.SetPoint(0, -64);
T.Move(96/2);
T.Turn(60);
T.Move(58/2);
T.Turn(30);
T.Move(32/2);
T.Turn(30);
T.Move(58/2);
T.Turn(30);
T.Move(58/2);
T.Turn(30);
T.Move(48/2);
T.SetAngle(0);//鼻
T.SetPoint(0, 0);
T.Move(32);
T.Turn(-160);
T.Move(34);
T.SetAngle(0);//口
T.SetPoint(0, -40);
T.Move(16);
T.Turn(32);
T.Move(24);
T.SetPoint(74, 64);//耳
T.SetAngle(8);
T.Move(32);
T.Turn(90);
T.Move(32);
T.Turn(45);
T.Move(32);
T.Turn(45);
T.Move(32);
T.Turn(90);
T.Move(32);
T.Turn(45);
T.Move(32);
T.SetPoint(77, 72);//耳内側
T.SetAngle(8);
T.Move(16);
T.Turn(90);
T.Move(16);
T.Turn(45);
T.Move(16);
T.Turn(45);
T.Move(16);
T.Turn(90);
T.Move(16);
T.Turn(45);
T.Move(16);
T.SetPoint(68, 0);//目
T.SetAngle(60);
T.Move(16);
T.Turn(30);
T.Move(24);
T.Turn(30);
T.Move(16);
T.Turn(60);
T.Move(16);
T.Turn(60);
T.Move(16);
T.Turn(30);
T.Move(24);
T.Turn(60);
T.Move(16);
T.Turn(30);
T.Move(16);
T.SetPoint(60, 40);//目
T.SetAngle(-90);
T.Move(30);
T.SetColor({ 255, 0 ,0 });
T.SetPoint(100, -58);//頬
T.SetAngle(60);
T.Move(16);
T.Turn(30);
T.Move(24);
T.Turn(30);
T.Move(16);
T.Turn(60);
T.Move(16);
T.Turn(60);
T.Move(16);
T.Turn(30);
T.Move(24);
T.Turn(60);
T.Move(16);
T.Turn(30);
T.Move(16);
T.SetTurnHorizon(true);
}
return true;
}
int main() {
Surface32 S(256, 256);
TortoiseGraphic T(&S);
std::ofstream fs("kumamon.ppm");
MakeHoge(T);
WritePPM(fs, S, "This is KUMAMON?");
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8ZnN0cmVhbT4KI2luY2x1ZGUgPHN0cmluZz4KLy8jaW5jbHVkZSAiVG9ydG9pc2UuaCIKCgovLyNwcmFnbWEgb25jZQojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8Y3N0ZGludD4KI2luY2x1ZGUgPGluaXRpYWxpemVyX2xpc3Q+CgpjbGFzcyBTdXJmYWNlMzIgewpwdWJsaWM6CglzdHJ1Y3QgRWxlbWVudCB7CgkJRWxlbWVudCgpIHsKCQkJdGhpcy0+dWkzMiA9IDB4ZmZmZmZmZmY7CgkJfQoJCUVsZW1lbnQoc3RkOjp1aW50MzJfdCBDb2xvcikgewoJCQl0aGlzLT51aTMyID0gQ29sb3I7CgkJfQoJCUVsZW1lbnQoc3RkOjp1aW50OF90IFIsIHN0ZDo6dWludDhfdCBHLCBzdGQ6OnVpbnQ4X3QgQikgewoJCQl0aGlzLT5SID0gUjsKCQkJdGhpcy0+RyA9IEc7CgkJCXRoaXMtPkIgPSBCOwoJCQl0aGlzLT5BID0gMHhmZjsKCQl9CgkJRWxlbWVudChzdGQ6OnVpbnQ4X3QgUiwgc3RkOjp1aW50OF90IEcsIHN0ZDo6dWludDhfdCBCLCBzdGQ6OnVpbnQ4X3QgQSkgewoJCQl0aGlzLT5SID0gUjsKCQkJdGhpcy0+RyA9IEc7CgkJCXRoaXMtPkIgPSBCOwoJCQl0aGlzLT5BID0gQTsKCQl9CgkJdW5pb24gewoJCQlzdHJ1Y3QKCQkJewoJCQkJc3RkOjp1aW50OF90IGIsIGcsIHIsIGE7Ly/jg5DjgqTjg4jjgqrjg7zjg4Djg7zjgYzntaHjgoDjgajjgY3jgYzjgYLjgovjga7jgafjgZPjgZPjga7kuKbjgbPjgYzlpKfkuovjgafjgZnvvIEKCQkJfTsKCQkJc3RydWN0CgkJCXsKCQkJCXN0ZDo6dWludDhfdCBCLCBHLCBSLCBBOy8v44GT44KM44KC77yBCgkJCX07CgkJCXN0ZDo6dWludDMyX3QgdWkzMjsKCQkJc3RkOjp1aW50OF90IHVpOGFbNF07CgkJfTsKCX07CnByb3RlY3RlZDoKCXR5cGVkZWYgc3RkOjp2ZWN0b3I8RWxlbWVudD4gUm93VHlwZTsKCXR5cGVkZWYgc3RkOjp2ZWN0b3I8Um93VHlwZT4gU3VyZmFjZTsKcHVibGljOgoJU3VyZmFjZTMyKCkgPSBkZWxldGU7CglTdXJmYWNlMzIoc3RkOjpzaXplX3QgV2lkdGgsIHN0ZDo6c2l6ZV90IEhlaWdodCkgewoJCVJlc2l6ZShXaWR0aCwgSGVpZ2h0KTsKCX0KCVN1cmZhY2UzMihzdGQ6OmluaXRpYWxpemVyX2xpc3Q8Um93VHlwZT4gaSkgOlMoaS5iZWdpbigpLCBpLmVuZCgpKSB7CgkJSCA9IGkuc2l6ZSgpOwoJCVcgPSAoKihpLmJlZ2luKCkpKS5zaXplKCk7CgkJUmVzaXplKFcsIEgpOwoJfQoJYm9vbCBSZXNpemUoc3RkOjpzaXplX3QgV2lkdGgsIHN0ZDo6c2l6ZV90IEhlaWdodCkgewoJCVcgPSBXaWR0aDsKCQlIID0gSGVpZ2h0OwoJCVMucmVzaXplKEhlaWdodCk7CgkJZm9yIChhdXRvJm8gOiBTKSB7CgkJCW8ucmVzaXplKFdpZHRoKTsKCQl9CgkJcmV0dXJuIHRydWU7Cgl9Cglib29sIEZpbGwoY29uc3QgRWxlbWVudCYgRSkgewoJCWZvciAoYXV0byZvbyA6IFMpIHsKCQkJZm9yIChhdXRvJm8gOiBvbykgewoJCQkJbyA9IEU7CgkJCX0KCQl9CgkJcmV0dXJuIHRydWU7Cgl9CgoJUm93VHlwZSYgb3BlcmF0b3IgW10oY29uc3Qgc3RkOjpzaXplX3QmIElkeCkgey8v44GT44Gu44Kk44Oz44OH44OD44Kv44K544Gv57im5pa55ZCR44KS5oyH5a6a44GX44Gm44GE44G+44GZ44CCCgkJcmV0dXJuIFNbSWR4XTsvL+i/lOOCi+OBruOBr+aoquaWueWQkeOBp+OBmeOAggoJfQoKCVN1cmZhY2U6Oml0ZXJhdG9yIGJlZ2luKCkgewoJCXJldHVybiBTLmJlZ2luKCk7Cgl9CglTdXJmYWNlOjppdGVyYXRvciBlbmQoKSB7CgkJcmV0dXJuIFMuZW5kKCk7Cgl9CglzdGQ6OnNpemVfdCBXaWR0aCgpIHsKCQlyZXR1cm4gVzsKCX0KCXN0ZDo6c2l6ZV90IEhlaWdodCgpIHsKCQlyZXR1cm4gSDsKCX0KCglib29sIFNldFBpeGVsKGNvbnN0IHN0ZDo6c2l6ZV90JiBYLCBjb25zdCBzdGQ6OnNpemVfdCYgWSwgY29uc3QgRWxlbWVudCYgRSkgewoJCWlmIChYID49IFcpIHJldHVybiBmYWxzZTsKCQlpZiAoWSA+PSBIKSByZXR1cm4gZmFsc2U7CgkJU1tZXVtYXSA9IEU7CgkJcmV0dXJuIHRydWU7Cgl9Cgpwcm90ZWN0ZWQ6CglzdGQ6OnNpemVfdCBXOwoJc3RkOjpzaXplX3QgSDsKCVN1cmZhY2UgUzsKfTsKI2luY2x1ZGUgPGNzdGRpbnQ+CiNpbmNsdWRlIDx0dXBsZT4KI2luY2x1ZGUgPGNtYXRoPgojaW5jbHVkZSA8YWxnb3JpdGhtPgovLyNpbmNsdWRlICJTdXJmYWNlMzIuaCIKCi8vcmVhZCB0aGlzLiBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4uby5qcC9kcC80Nzc0MTM2MTgyCi8vYnV0IGphcGFuZXNlLgoKY2xhc3MgVG9ydG9pc2VHcmFwaGljIHsKcHVibGljOgoJdHlwZWRlZiBzdGQ6OnR1cGxlIDxkb3VibGUsIGRvdWJsZT4gVmVjdG9yMkQ7CnB1YmxpYzoKCVRvcnRvaXNlR3JhcGhpYygpID0gZGVsZXRlOwoJVG9ydG9pc2VHcmFwaGljKFN1cmZhY2UzMiogU2NyZWVuKSA6UyhTY3JlZW4pLCBBbmdsZSgpLCBUdXJuSG9yaXpvbihmYWxzZSksIFR1cm5WZXJ0aWNhbCh0cnVlKSB7fQoKCWJvb2wgU2V0UGl4ZWwoY29uc3Qgc3RkOjppbnQ2NF90JiBYLCBjb25zdCBzdGQ6OmludDY0X3QmIFksIGNvbnN0IFN1cmZhY2UzMjo6RWxlbWVudCYgRSwgYm9vbCBUcmFuY2Vmb3JtID0gdHJ1ZSkgewoJCWlmIChTID09IG51bGxwdHIpcmV0dXJuIGZhbHNlOwoJCXN0ZDo6aW50NjRfdCBBID0gWDsKCQlzdGQ6OmludDY0X3QgQiA9IFk7CgkJaWYgKFRyYW5jZWZvcm0gPT0gdHJ1ZSkgewoJCQlkb3VibGUgT1gsIE9ZOwoJCQlzdGQ6OnRpZShPWCwgT1kpID0gT3JpZ2luOwoJCQlBID0gc3RhdGljX2Nhc3Q8c3RkOjppbnQ2NF90PihYICsgT1gpOwoJCQlpZiAoVHVybkhvcml6b24gPT0gdHJ1ZSkgQSA9IFMtPldpZHRoKCkgLSBBOwoJCQlCID0gc3RhdGljX2Nhc3Q8c3RkOjppbnQ2NF90PihZICsgT1kpOwoJCQlpZiAoVHVyblZlcnRpY2FsID09IHRydWUpIEIgPSBTLT5IZWlnaHQoKSAtIEI7CgkJfQoKCQlyZXR1cm4gUy0+U2V0UGl4ZWwoQSwgQiwgRSk7Cgl9CglTdXJmYWNlMzI6OkVsZW1lbnQgR2V0UGl4ZWwoY29uc3Qgc3RkOjppbnQ2NF90JiBYLCBjb25zdCBzdGQ6OmludDY0X3QmIFksIGJvb2wgVHJhbmNlZm9ybSA9IHRydWUpIHsKCQlpZiAoUyA9PSBudWxscHRyKXJldHVybiBmYWxzZTsKCQlzdGQ6OmludDY0X3QgQSA9IFg7CgkJc3RkOjppbnQ2NF90IEIgPSBZOwoJCWlmIChUcmFuY2Vmb3JtID09IHRydWUpIHsKCQkJZG91YmxlIE9YLCBPWTsKCQkJc3RkOjp0aWUoT1gsIE9ZKSA9IE9yaWdpbjsKCgkJCUEgPSBzdGF0aWNfY2FzdDxzdGQ6OmludDY0X3Q+KFggKyBPWCk7CgkJCWlmIChUdXJuSG9yaXpvbiA9PSB0cnVlKSBBID0gUy0+V2lkdGgoKSAtIEE7CgkJCUIgPSBzdGF0aWNfY2FzdDxzdGQ6OmludDY0X3Q+KFkgKyBPWSk7CgkJCWlmIChUdXJuVmVydGljYWwgPT0gdHJ1ZSkgQiA9IFMtPkhlaWdodCgpIC0gQjsKCQl9CgkJLy8vLy8vLy8vLy8vLy8KCQlpZiAoQSA8IDApIHJldHVybiAweDAwMDAwMDAwOwoJCWlmIChBID49IFMtPldpZHRoKCkpIHJldHVybiAweDAwMDAwMDAwOwoJCWlmIChCIDwgMCkgcmV0dXJuIDB4MDAwMDAwMDA7CgkJaWYgKEIgPj0gUy0+SGVpZ2h0KCkpIHJldHVybiAweDAwMDAwMDAwOwoKCgoJCXJldHVybiAoKlMpW0JdW0FdOwoJfQoJYm9vbCBTZXRUdXJuVmVydGljYWwoYm9vbCBGID0gdHJ1ZSkgewoJCVR1cm5WZXJ0aWNhbCA9IEY7CgkJcmV0dXJuIHRydWU7Cgl9Cglib29sIEdldFR1cm5WZXJ0aWNhbCgpIHsKCQlyZXR1cm4gVHVyblZlcnRpY2FsOwoJfQoJYm9vbCBTZXRUdXJuSG9yaXpvbihib29sIEYgPSBmYWxzZSkgewoJCVR1cm5Ib3Jpem9uID0gRjsKCQlyZXR1cm4gdHJ1ZTsKCX0KCWJvb2wgR2V0VHVybkhvcml6b24oKSB7CgkJcmV0dXJuIFR1cm5Ib3Jpem9uOwoJfQoKCWJvb2wgU2V0QW5nbGUoZG91YmxlIEEpIHsKCQlBbmdsZSA9IEE7CgkJcmV0dXJuIHRydWU7Cgl9Cglib29sIFR1cm4oZG91YmxlIEEpIHsKCQlBbmdsZSArPSBBOwoJCUFuZ2xlID0gc3RkOjpmbW9kKEFuZ2xlLCAzNjApOwoJCXJldHVybiB0cnVlOwoJfQoJYm9vbCBTZXRQb2ludChkb3VibGUgWCwgZG91YmxlIFkpIHsKCQlOb3cgPSBzdGQ6Om1ha2VfdHVwbGUoWCwgWSk7CgkJcmV0dXJuIHRydWU7Cgl9CglWZWN0b3IyRCBHZXRQb2ludCgpIHsKCQlyZXR1cm4gTm93OwoJfQoJYm9vbCBTZXRPcmlnaW4oZG91YmxlIFgsIGRvdWJsZSBZKSB7CgkJT3JpZ2luID0gc3RkOjptYWtlX3R1cGxlKFgsIFkpOwoJCXJldHVybiB0cnVlOwoJfQoJVmVjdG9yMkQgR2V0T3JpZ2luKCkgewoJCXJldHVybiBPcmlnaW47Cgl9CgoJYm9vbCBTZXRDb2xvcihjb25zdCBTdXJmYWNlMzI6OkVsZW1lbnQmIENvbG9yKSB7CgkJQyA9IENvbG9yOwoJCXJldHVybiB0cnVlOwoJfQoJU3VyZmFjZTMyOjpFbGVtZW50IEdldENvbG9yKCkgewoJCXJldHVybiBDOwoJfQoJYm9vbCBMaW5lKHN0ZDo6aW50NjRfdCB4MCwgc3RkOjppbnQ2NF90IHkwLCBzdGQ6OmludDY0X3QgeDEsIHN0ZDo6aW50NjRfdCB5MSwgYm9vbCBJbkRpcmVjdCA9IGZhbHNlKSB7CgkJc3RkOjppbnQ2NF90IGR4ID0gc3RkOjphYnMoeDEgLSB4MCk7CgkJc3RkOjppbnQ2NF90IGR5ID0gc3RkOjphYnMoeTEgLSB5MCk7CgkJc3RkOjppbnQ2NF90IHN4LCBzeTsKCQlpZiAoeDAgPCB4MSkgeyBzeCA9IDE7IH0KCQllbHNlIHsgc3ggPSAtMTsgfQoJCWlmICh5MCA8IHkxKSB7IHN5ID0gMTsgfQoJCWVsc2UgeyBzeSA9IC0xOyB9CgkJc3RkOjppbnQ2NF90IGVyciA9IGR4IC0gZHk7CgkJd2hpbGUgKHRydWUpIHsKCQkJU2V0UGl4ZWwoeDAsIHkwLCBDLCAhSW5EaXJlY3QpOwoJCQlpZiAoKHgwID09IHgxKSAmJiAoeTAgPT0geTEpKSBicmVhazsKCQkJc3RkOjppbnQ2NF90IGUyID0gMiAqIGVycjsKCQkJaWYgKGUyID4gLWR5KSB7CgkJCQllcnIgPSBlcnIgLSBkeTsKCQkJCXgwICs9IHN4OwoJCQl9CgkJCWlmIChlMiA8IGR4KSB7CgkJCQllcnIgPSBlcnIgKyBkeDsKCQkJCXkwICs9IHN5OwoJCQl9CgkJfQoJCXJldHVybiB0cnVlOwoJfQoKCWJvb2wgTW92ZShkb3VibGUgTCkgewoJCWRvdWJsZSBOeCwgTnk7CgkJc3RkOjp0aWUoTngsIE55KSA9IE5vdzsKCQlkb3VibGUgWCA9IEwgKiBzdGQ6OmNvcyhSYWQqQW5nbGUpOwoJCWRvdWJsZSBZID0gTCAqIHN0ZDo6c2luKFJhZCpBbmdsZSk7CgoJCUxpbmUoTngsIE55LCBOeCArIFgsIE55ICsgWSk7CgkJU2V0UG9pbnQoTnggKyBYLCBOeSArIFkpOwoJCXJldHVybiB0cnVlOwoJfQoJYm9vbCBNb3ZlVG8oZG91YmxlIFgsIGRvdWJsZSBZKSB7CgkJZG91YmxlIE54LCBOeTsKCQlzdGQ6OnRpZShOeCwgTnkpID0gTm93OwoJCUxpbmUoTngsIE55LCBYLCBZKTsKCQlTZXRQb2ludChYLCBZKTsKCQlyZXR1cm4gdHJ1ZTsKCX0KCWJvb2wgQ2xlYXIoKSB7CgkJaWYgKFMgPT0gbnVsbHB0cikgcmV0dXJuIGZhbHNlOwoJCVMtPkZpbGwoQyk7CgkJcmV0dXJuIHRydWU7Cgl9Cglib29sIENsZWFyVW5kZXJGbG9hdGluZ1BvaW50KCkgewoJCWRvdWJsZSBYLCBZOwoJCXN0ZDo6dGllKFgsIFkpID0gTm93OwoJCU5vdyA9IHN0ZDo6bWFrZV90dXBsZShzdGQ6OmZsb29yKFgpLCBzdGQ6OmZsb29yKFkpKTsKCQlyZXR1cm4gdHJ1ZTsKCX0KCVN1cmZhY2UzMiogR2V0U3VyZmFjZSgpIHsKCQlyZXR1cm4gUzsKCX0KCnByb3RlY3RlZDoKCVN1cmZhY2UzMiogUzsKCWRvdWJsZSBBbmdsZTsKCVZlY3RvcjJEIE5vdzsKCVZlY3RvcjJEIE9yaWdpbjsKCWJvb2wgVHVyblZlcnRpY2FsOwoJYm9vbCBUdXJuSG9yaXpvbjsKCWRvdWJsZSBQSSA9IDMuMTQxNTkyNjUzNTk7Cglkb3VibGUgUmFkID0gUEkgLyAxODAuMDsKCVN1cmZhY2UzMjo6RWxlbWVudCBDOwp9OwoKYm9vbCBXcml0ZVBQTShzdGQ6Om9zdHJlYW0mIG9zLCBTdXJmYWNlMzImIFMsIHN0ZDo6c3RyaW5nIGNvbW1lbnQgPSAiTm8gQ29tbWVudCIpIHsKCgkvL3dyaXRlIGhlYWRlcgoJb3MgPDwgIlAzIiA8PCBzdGQ6OmVuZGw7CgkvL3dyaXRlIGNvbW1lbnQKCW9zIDw8ICIjIiA8PCBjb21tZW50IDw8IHN0ZDo6ZW5kbDsKCS8vd3JpdGUgc2l6ZQoJb3MgPDwgUy5XaWR0aCgpIDw8ICcgJyA8PCBTLkhlaWdodCgpIDw8IHN0ZDo6ZW5kbDsKCS8vYnl0ZW1heAoJb3MgPDwgIjI1NSIgPDwgc3RkOjplbmRsOwoKCWZvciAoYXV0byYgb28gOiBTKSB7CgkJZm9yIChhdXRvJiBvIDogb28pIHsKCQkJb3MgPDwgc3RhdGljX2Nhc3Q8c3RkOjppbnQxNl90PihvLlIpIDw8ICcgJyA8PCBzdGF0aWNfY2FzdDxzdGQ6OmludDE2X3Q+KG8uRykgPDwgJyAnIDw8IHN0YXRpY19jYXN0PHN0ZDo6aW50MTZfdD4oby5CKSA8PCBzdGQ6OmVuZGw7CgkJfQoJfQoKCXJldHVybiB0cnVlOwp9Cgpib29sIE1ha2VIb2dlKFRvcnRvaXNlR3JhcGhpYyYgVCkgewoJCglULlNldE9yaWdpbihULkdldFN1cmZhY2UoKS0+V2lkdGgoKSAvIDIsIFQuR2V0U3VyZmFjZSgpLT5IZWlnaHQoKSAvIDIpOwoJVC5TZXRUdXJuVmVydGljYWwoKTsKCglmb3IgKGludCBpID0gMDsgaSA8IDI7IGkrKykgewoJCVQuU2V0Q29sb3IoeyAwLDAsMCwgfSk7CgkJVC5TZXRBbmdsZSgwKTsvL+i8qumDrQoJCVQuU2V0UG9pbnQoMCwgLTgwKTsKCQlULk1vdmUoOTYpOwoJCVQuVHVybig2MCk7CgkJVC5Nb3ZlKDU4KTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSgzMik7CgkJVC5UdXJuKDMwKTsKCQlULk1vdmUoNTgpOwoJCVQuVHVybigzMCk7CgkJVC5Nb3ZlKDU4KTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSg0OCk7CQoKCQlULlNldEFuZ2xlKDApOy8v6Lyq6YOtCgkJVC5TZXRQb2ludCgwLCAtNjQpOwoJCVQuTW92ZSg5Ni8yKTsKCQlULlR1cm4oNjApOwoJCVQuTW92ZSg1OC8yKTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSgzMi8yKTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSg1OC8yKTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSg1OC8yKTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSg0OC8yKTsKCgkJVC5TZXRBbmdsZSgwKTsvL+m8uwoJCVQuU2V0UG9pbnQoMCwgMCk7CgkJVC5Nb3ZlKDMyKTsKCQlULlR1cm4oLTE2MCk7CgkJVC5Nb3ZlKDM0KTsJCgoJCVQuU2V0QW5nbGUoMCk7Ly/lj6MKCQlULlNldFBvaW50KDAsIC00MCk7CgkJVC5Nb3ZlKDE2KTsKCQlULlR1cm4oMzIpOwoJCVQuTW92ZSgyNCk7CQoKCQlULlNldFBvaW50KDc0LCA2NCk7Ly/ogLMKCQlULlNldEFuZ2xlKDgpOwkJCgkJVC5Nb3ZlKDMyKTsKCQlULlR1cm4oOTApOwoJCVQuTW92ZSgzMik7CgkJVC5UdXJuKDQ1KTsKCQlULk1vdmUoMzIpOwoJCVQuVHVybig0NSk7CgkJVC5Nb3ZlKDMyKTsJCgkJVC5UdXJuKDkwKTsKCQlULk1vdmUoMzIpOwoJCVQuVHVybig0NSk7CgkJVC5Nb3ZlKDMyKTsKCgkJVC5TZXRQb2ludCg3NywgNzIpOy8v6ICz5YaF5YG0CgkJVC5TZXRBbmdsZSg4KTsJCQoJCVQuTW92ZSgxNik7CgkJVC5UdXJuKDkwKTsKCQlULk1vdmUoMTYpOwoJCVQuVHVybig0NSk7CgkJVC5Nb3ZlKDE2KTsKCQlULlR1cm4oNDUpOwoJCVQuTW92ZSgxNik7CQoJCVQuVHVybig5MCk7CgkJVC5Nb3ZlKDE2KTsKCQlULlR1cm4oNDUpOwoJCVQuTW92ZSgxNik7CgoJCVQuU2V0UG9pbnQoNjgsIDApOy8v55uuCgkJVC5TZXRBbmdsZSg2MCk7CQkKCQlULk1vdmUoMTYpOwoJCVQuVHVybigzMCk7CgkJVC5Nb3ZlKDI0KTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSgxNik7CgkJVC5UdXJuKDYwKTsKCQlULk1vdmUoMTYpOwkKCQlULlR1cm4oNjApOwoJCVQuTW92ZSgxNik7CgkJVC5UdXJuKDMwKTsKCQlULk1vdmUoMjQpOwkJCgkJVC5UdXJuKDYwKTsKCQlULk1vdmUoMTYpOwoJCVQuVHVybigzMCk7CgkJVC5Nb3ZlKDE2KTsKCgkJVC5TZXRQb2ludCg2MCwgNDApOy8v55uuCgkJVC5TZXRBbmdsZSgtOTApOwoJCVQuTW92ZSgzMCk7CgoJCVQuU2V0Q29sb3IoeyAyNTUsIDAgLDAgfSk7CgkJVC5TZXRQb2ludCgxMDAsIC01OCk7Ly/poKwKCQlULlNldEFuZ2xlKDYwKTsJCQoJCVQuTW92ZSgxNik7CgkJVC5UdXJuKDMwKTsKCQlULk1vdmUoMjQpOwoJCVQuVHVybigzMCk7CgkJVC5Nb3ZlKDE2KTsKCQlULlR1cm4oNjApOwoJCVQuTW92ZSgxNik7CQoJCVQuVHVybig2MCk7CgkJVC5Nb3ZlKDE2KTsKCQlULlR1cm4oMzApOwoJCVQuTW92ZSgyNCk7CQkKCQlULlR1cm4oNjApOwoJCVQuTW92ZSgxNik7CgkJVC5UdXJuKDMwKTsKCQlULk1vdmUoMTYpOwoJCQoJCQoKCQlULlNldFR1cm5Ib3Jpem9uKHRydWUpOwoKCgoJfQoJcmV0dXJuIHRydWU7Cn0KCmludCBtYWluKCkgewoJCglTdXJmYWNlMzIgUygyNTYsIDI1Nik7CglUb3J0b2lzZUdyYXBoaWMgVCgmUyk7CglzdGQ6Om9mc3RyZWFtIGZzKCJrdW1hbW9uLnBwbSIpOwoKCU1ha2VIb2dlKFQpOwoJCglXcml0ZVBQTShmcywgUywgIlRoaXMgaXMgS1VNQU1PTj8iKTsKfQ==