// you'd better compile me with speed optimizations on :D
#include <SFML/Graphics.hpp>
#include <algorithm>
#include <vector>
#include <map>
#include <cstdlib>
#include <ctime>
#include <cmath>
void noise(sf::Image & image) {
const int width = image.GetWidth();
const int height = image.GetHeight();
for (int i = 0; i < width; ++ i) {
for (int j = 0; j < height; ++ j) {
int val = std::rand() % 256;
image.SetPixel(i, j, sf::Color(val, val, val));
}
}
}
void wall(sf::Image & image, bool cool) {
std::map<int, int> interiorId2offset;
const int width = image.GetWidth();
const int height = image.GetHeight();
for (int i = 0; i < width; ++ i) {
for (int j = 0; j < height; ++ j) {
int val = 0;
int offset = 0;
if (j % 128 < 64) offset = 40;
bool one = ((i + offset) % 128 < 2 || (i + offset) % 128 > 126);
bool two = ( j % 64 < 2 || j % 64 > 62);
bool nearOne = (i % 128 < 8 || i % 128 > 120);
bool nearTwo = (j % 64 < 8 || j % 64 > 56);
if (one && !nearTwo || two && !nearOne) val = 225;
bool interior = !one && !two;
if (interior) {
int x = (i + offset) / 128;
int y = j / 64;
if (x >= width / 128) x = 0; // in order to be tileable
int interiorOffset = interiorId2offset[x + 100 * y];
if (interiorOffset == 0) {
interiorOffset = std::rand() % 3 * 30 + 1;
interiorId2offset[x + 100 * y] = interiorOffset;
}
val = ((i + offset) % 128 + j % 64 + interiorOffset) % 256;
if (val < 25) val = 25;
if (val > 175) val = 175;
}
if (cool) val = (val + std::rand() % 15 + 35) % 256;
image.SetPixel(i, j, sf::Color(val, val, val));
}
}
}
void whiteDrops(sf::Image & image, int count, int minSize, int maxSize, bool filled = true, int thickness = 0) {
const int width = image.GetWidth();
const int height = image.GetHeight();
for (int i = 0; i < count; ++ i) {
int cx = std::rand() % width;
int cy = std::rand() % height;
int size = std::rand() % (maxSize - minSize + 1) + minSize;
for (int x = cx - size; x <= cx + size; ++ x) {
for (int y = cy - size; y <= cy + size; ++ y) {
int d2 = (x - cx) * (x - cx) + (y - cy) * (y - cy);
int s2 = size * size;
if (d2 <= s2) {
int px = (x % width + width) % width;
int py = (y % height + height) % height;
if (d2 <= s2 - thickness) {
if (filled)
image.SetPixel(px, py, sf::Color::Black);
} else {
image.SetPixel(px, py, sf::Color::White);
}
}
}
}
}
}
void bit(sf::Image & image, int a, int b, int c) {
const int width = image.GetWidth();
const int height = image.GetHeight();
for (int i = 0; i < width; ++ i) {
for (int j = 0; j < height; ++ j) {
int val = (a * (i & j) + b * (i ^ j) + c * (i | j)) % 256;
image.SetPixel(i, j, sf::Color(val, val, val));
}
}
}
void median(sf::Image & image, int size, bool red = true, bool green = true, bool blue = true) {
sf::Image image2(image);
const int width = image.GetWidth();
const int height = image.GetHeight();
for (int i = 0; i < width; ++ i) {
for (int j = 0; j < height; ++ j) {
std::vector<int> rs, gs, bs;
sf::Color c;
for (int x = -size; x <= size; ++ x) {
for (int y = -size; y <= size; ++ y) {
int a = ((x + i) % width + width) % width;
int b = ((y + j) % height + height) % height;
c = image2.GetPixel(a, b);
rs.push_back(c.r);
gs.push_back(c.g);
bs.push_back(c.b);
}
}
c = image2.GetPixel(i, j);
if (red) {
std::sort(rs.begin(), rs.end());
c.r = rs[rs.size() / 2];
}
if (green) {
std::sort(gs.begin(), gs.end());
c.g = gs[gs.size() / 2];
}
if (blue) {
std::sort(bs.begin(), bs.end());
c.b = bs[bs.size() / 2];
}
image.SetPixel(i, j, c);
}
}
}
void blend(sf::Image & dest, sf::Image source1, sf::Image source2, int w1, int w2) {
const int width = dest.GetWidth();
const int height = dest.GetHeight();
for (int i = 0; i < width; ++ i) {
for (int j = 0; j < height; ++ j) {
int r = 0, g = 0, b = 0;
sf::Color p1 = source1.GetPixel(i, j);
sf::Color p2 = source2.GetPixel(i, j);
r += w1 * p1.r;
r += w2 * p2.r;
g += w1 * p1.g;
g += w2 * p2.g;
b += w1 * p1.b;
b += w2 * p2.b;
r /= (w1 + w2);
g /= (w1 + w2);
b /= (w1 + w2);
dest.SetPixel(i, j, sf::Color(r, g, b));
}
}
}
void pixelize(sf::Image & image, int size) {
const int width = image.GetWidth();
const int height = image.GetHeight();
sf::Image image2(image);
for (int i = 0; i < width; i += size) {
for (int j = 0; j < height; j += size) {
sf::Color curColor = image2.GetPixel(i, j);
for (int x = 0; x < size; ++ x) {
for (int y = 0; y < size; ++ y) {
int a = ((x + i) % width + width) % width;
int b = ((y + j) % height + height) % height;
image.SetPixel(a, b, curColor);
}
}
}
}
}
void magnifyingDrops(sf::Image & image, int count, int minSize, int maxSize, double exponent) {
const int width = image.GetWidth();
const int height = image.GetHeight();
sf::Image image2(image);
for (int i = 0; i < count; ++ i) {
int cx = std::rand() % width;
int cy = std::rand() % height;
int size = std::rand() % (maxSize - minSize + 1) + minSize;
int s2 = size * size;
double m = std::pow(size, 1 - exponent);
for (int x = - size; x <= size; ++ x) {
for (int y = - size; y <= size; ++ y) {
int signx = x < 0 ? -1 : 1;
int signy = y < 0 ? -1 : 1;
int d2 = x * x + y * y;
if (d2 > s2) continue;
int sx = (int(cx + signx * std::pow(signx * x, exponent) * m) % width + width) % width;
int sy = (int(cy + signy * std::pow(signy * y, exponent) * m) % height + height) % height;
int tx = ((cx + x) % width + width) % width;
int ty = ((cy + y) % height + height) % height;
image.SetPixel(tx, ty, image2.GetPixel(sx, sy));
}
}
}
}
int main()
{
std::srand(std::time(0));
const int width = 512;
const int height = 256;
sf::Image txt_bit(width, height, sf::Color::Black);
sf::Image txt_wall(width, height, sf::Color::Black);
sf::Image txt_noise(width, height, sf::Color::Black);
sf::Image txt_drops(width, height, sf::Color::Black);
sf::Image txt_result(width, height, sf::Color::Black);
txt_bit.SetSmooth(false);
txt_wall.SetSmooth(false);
txt_noise.SetSmooth(false);
txt_drops.SetSmooth(false);
txt_result.SetSmooth(false);
/*
bit(txt_bit, 16, 64, 32);
median(txt_bit, 2);
//*/
/*
bit(txt_bit, 32, 64, 16);
median(txt_bit, 2);
//*/
/*
bit(txt_bit, 64, 32, 16);
median(txt_bit, 2);
//*/
/*
bit(txt_bit, 4, 8, 16);
median(txt_bit, 1);
median(txt_bit, 1);
//*/
/*
bit(txt_bit, 16, 8, 16);
median(txt_bit, 1);
median(txt_bit, 1);
//*/
/*
bit(txt_bit, 15, 16, 17);
median(txt_bit, 1);
median(txt_bit, 1);
median(txt_bit, 1);
//*/
///*
bit(txt_bit, 35, 70, 140);
median(txt_bit, 1);
median(txt_bit, 2);
//*/
wall(txt_wall, true);
noise(txt_noise);
whiteDrops(txt_drops, 250, 40, 80, false, 125);
blend(txt_result, txt_drops, txt_noise, 15, 5);
median(txt_result, 1);
blend(txt_result, txt_wall, txt_result, 13, 2);
magnifyingDrops(txt_result, 10, 40, 50, 1.15);
pixelize(txt_result, 4);
sf::Sprite sprite(txt_result);
//pixelize(txt_bit, 2);
//sf::Sprite sprite(txt_bit);
sf::RenderWindow window(sf::VideoMode(width * 2, height * 2, 32), "Procedural Textures!");
window.UseVerticalSync(true);
bool Running = true;
while (Running)
{
sf::Event Event;
while (window.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
Running = false;
if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
Running = false;
}
window.Clear();
window.Draw(sprite);
sprite.Move(width, 0);
window.Draw(sprite);
sprite.Move(0, height);
window.Draw(sprite);
sprite.Move(- width, 0);
window.Draw(sprite);
sprite.Move(0, - height);
window.Display();
}
}
Ly8geW91J2QgYmV0dGVyIGNvbXBpbGUgbWUgd2l0aCBzcGVlZCBvcHRpbWl6YXRpb25zIG9uIDpECgojaW5jbHVkZSA8U0ZNTC9HcmFwaGljcy5ocHA+CiNpbmNsdWRlIDxhbGdvcml0aG0+CiNpbmNsdWRlIDx2ZWN0b3I+CiNpbmNsdWRlIDxtYXA+CiNpbmNsdWRlIDxjc3RkbGliPgojaW5jbHVkZSA8Y3RpbWU+CiNpbmNsdWRlIDxjbWF0aD4KCnZvaWQgbm9pc2Uoc2Y6OkltYWdlICYgaW1hZ2UpIHsKCiAgICBjb25zdCBpbnQgd2lkdGggPSBpbWFnZS5HZXRXaWR0aCgpOwogICAgY29uc3QgaW50IGhlaWdodCA9IGltYWdlLkdldEhlaWdodCgpOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd2lkdGg7ICsrIGkpIHsKICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IGhlaWdodDsgKysgaikgewoKICAgICAgICAgICAgaW50IHZhbCA9IHN0ZDo6cmFuZCgpICUgMjU2OwoKICAgICAgICAgICAgaW1hZ2UuU2V0UGl4ZWwoaSwgaiwgc2Y6OkNvbG9yKHZhbCwgdmFsLCB2YWwpKTsKICAgICAgICB9CiAgICB9Cn0KCnZvaWQgd2FsbChzZjo6SW1hZ2UgJiBpbWFnZSwgYm9vbCBjb29sKSB7CgogICAgc3RkOjptYXA8aW50LCBpbnQ+IGludGVyaW9ySWQyb2Zmc2V0OwoKICAgIGNvbnN0IGludCB3aWR0aCA9IGltYWdlLkdldFdpZHRoKCk7CiAgICBjb25zdCBpbnQgaGVpZ2h0ID0gaW1hZ2UuR2V0SGVpZ2h0KCk7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3aWR0aDsgKysgaSkgewogICAgICAgIGZvciAoaW50IGogPSAwOyBqIDwgaGVpZ2h0OyArKyBqKSB7CgogICAgICAgICAgICBpbnQgdmFsID0gMDsKICAgICAgICAgICAgaW50IG9mZnNldCA9IDA7CgogICAgICAgICAgICBpZiAoaiAlIDEyOCA8IDY0KSBvZmZzZXQgPSA0MDsKCiAgICAgICAgICAgIGJvb2wgb25lID0gKChpICsgb2Zmc2V0KSAlIDEyOCA8IDIgfHwgKGkgKyBvZmZzZXQpICUgMTI4ID4gMTI2KTsKICAgICAgICAgICAgYm9vbCB0d28gPSAoIGogICAgICAgICAgICUgIDY0IDwgMiB8fCAgaiAgICAgICAgICAgJSAgNjQgPiAgNjIpOwoKICAgICAgICAgICAgYm9vbCBuZWFyT25lID0gKGkgJSAxMjggPCA4IHx8IGkgJSAxMjggPiAxMjApOwogICAgICAgICAgICBib29sIG5lYXJUd28gPSAoaiAlICA2NCA8IDggfHwgaiAlICA2NCA+ICA1Nik7CgogICAgICAgICAgICBpZiAob25lICYmICFuZWFyVHdvIHx8IHR3byAmJiAhbmVhck9uZSkgdmFsID0gMjI1OwoKICAgICAgICAgICAgYm9vbCBpbnRlcmlvciA9ICFvbmUgJiYgIXR3bzsKCiAgICAgICAgICAgIGlmIChpbnRlcmlvcikgewoKICAgICAgICAgICAgICAgIGludCB4ID0gKGkgKyBvZmZzZXQpIC8gMTI4OwogICAgICAgICAgICAgICAgaW50IHkgPSAgaiAgICAgICAgICAgLyAgNjQ7CgogICAgICAgICAgICAgICAgaWYgKHggPj0gd2lkdGggLyAxMjgpIHggPSAwOyAvLyBpbiBvcmRlciB0byBiZSB0aWxlYWJsZQoKICAgICAgICAgICAgICAgIGludCBpbnRlcmlvck9mZnNldCA9IGludGVyaW9ySWQyb2Zmc2V0W3ggKyAxMDAgKiB5XTsKCiAgICAgICAgICAgICAgICBpZiAoaW50ZXJpb3JPZmZzZXQgPT0gMCkgewoKICAgICAgICAgICAgICAgICAgICBpbnRlcmlvck9mZnNldCA9IHN0ZDo6cmFuZCgpICUgMyAqIDMwICsgMTsKICAgICAgICAgICAgICAgICAgICBpbnRlcmlvcklkMm9mZnNldFt4ICsgMTAwICogeV0gPSBpbnRlcmlvck9mZnNldDsKICAgICAgICAgICAgICAgIH0KCiAgICAgICAgICAgICAgICB2YWwgPSAoKGkgKyBvZmZzZXQpICUgMTI4ICsgaiAlIDY0ICsgaW50ZXJpb3JPZmZzZXQpICUgMjU2OwoKICAgICAgICAgICAgICAgIGlmICh2YWwgPCAgMjUpIHZhbCA9ICAyNTsKICAgICAgICAgICAgICAgIGlmICh2YWwgPiAxNzUpIHZhbCA9IDE3NTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKGNvb2wpIHZhbCA9ICh2YWwgKyBzdGQ6OnJhbmQoKSAlIDE1ICsgMzUpICUgMjU2OwoKICAgICAgICAgICAgaW1hZ2UuU2V0UGl4ZWwoaSwgaiwgc2Y6OkNvbG9yKHZhbCwgdmFsLCB2YWwpKTsKICAgICAgICB9CiAgICB9Cn0KCnZvaWQgd2hpdGVEcm9wcyhzZjo6SW1hZ2UgJiBpbWFnZSwgaW50IGNvdW50LCBpbnQgbWluU2l6ZSwgaW50IG1heFNpemUsIGJvb2wgZmlsbGVkID0gdHJ1ZSwgaW50IHRoaWNrbmVzcyA9IDApIHsKCiAgICBjb25zdCBpbnQgd2lkdGggPSBpbWFnZS5HZXRXaWR0aCgpOwogICAgY29uc3QgaW50IGhlaWdodCA9IGltYWdlLkdldEhlaWdodCgpOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgY291bnQ7ICsrIGkpIHsKCiAgICAgICAgaW50IGN4ID0gc3RkOjpyYW5kKCkgJSB3aWR0aDsKICAgICAgICBpbnQgY3kgPSBzdGQ6OnJhbmQoKSAlIGhlaWdodDsKCiAgICAgICAgaW50IHNpemUgPSBzdGQ6OnJhbmQoKSAlIChtYXhTaXplIC0gbWluU2l6ZSArIDEpICsgbWluU2l6ZTsKCiAgICAgICAgZm9yIChpbnQgeCA9IGN4IC0gc2l6ZTsgeCA8PSBjeCArIHNpemU7ICsrIHgpIHsKICAgICAgICAgICAgZm9yIChpbnQgeSA9IGN5IC0gc2l6ZTsgeSA8PSBjeSArIHNpemU7ICsrIHkpIHsKCiAgICAgICAgICAgICAgICBpbnQgZDIgPSAoeCAtIGN4KSAqICh4IC0gY3gpICsgKHkgLSBjeSkgKiAoeSAtIGN5KTsKICAgICAgICAgICAgICAgIGludCBzMiA9IHNpemUgKiBzaXplOwoKICAgICAgICAgICAgICAgIGlmIChkMiA8PSBzMikgewoKICAgICAgICAgICAgICAgICAgICBpbnQgcHggPSAoeCAlIHdpZHRoICsgd2lkdGgpICUgd2lkdGg7CiAgICAgICAgICAgICAgICAgICAgaW50IHB5ID0gKHkgJSBoZWlnaHQgKyBoZWlnaHQpICUgaGVpZ2h0OwoKICAgICAgICAgICAgICAgICAgICBpZiAoZDIgPD0gczIgLSB0aGlja25lc3MpIHsKICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZpbGxlZCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlLlNldFBpeGVsKHB4LCBweSwgc2Y6OkNvbG9yOjpCbGFjayk7CiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2UuU2V0UGl4ZWwocHgsIHB5LCBzZjo6Q29sb3I6OldoaXRlKTsKICAgICAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KCnZvaWQgYml0KHNmOjpJbWFnZSAmIGltYWdlLCBpbnQgYSwgaW50IGIsIGludCBjKSB7CgogICAgY29uc3QgaW50IHdpZHRoID0gaW1hZ2UuR2V0V2lkdGgoKTsKICAgIGNvbnN0IGludCBoZWlnaHQgPSBpbWFnZS5HZXRIZWlnaHQoKTsKCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHdpZHRoOyArKyBpKSB7CiAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBoZWlnaHQ7ICsrIGopIHsKCiAgICAgICAgICAgIGludCB2YWwgPSAoYSAqIChpICYgaikgKyBiICogKGkgXiBqKSArIGMgKiAoaSB8IGopKSAlIDI1NjsKCiAgICAgICAgICAgIGltYWdlLlNldFBpeGVsKGksIGosIHNmOjpDb2xvcih2YWwsIHZhbCwgdmFsKSk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIG1lZGlhbihzZjo6SW1hZ2UgJiBpbWFnZSwgaW50IHNpemUsIGJvb2wgcmVkID0gdHJ1ZSwgYm9vbCBncmVlbiA9IHRydWUsIGJvb2wgYmx1ZSA9IHRydWUpIHsKCiAgICBzZjo6SW1hZ2UgaW1hZ2UyKGltYWdlKTsKCiAgICBjb25zdCBpbnQgd2lkdGggPSBpbWFnZS5HZXRXaWR0aCgpOwogICAgY29uc3QgaW50IGhlaWdodCA9IGltYWdlLkdldEhlaWdodCgpOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgd2lkdGg7ICsrIGkpIHsKICAgICAgICBmb3IgKGludCBqID0gMDsgaiA8IGhlaWdodDsgKysgaikgewoKICAgICAgICAgICAgc3RkOjp2ZWN0b3I8aW50PiBycywgZ3MsIGJzOwoKICAgICAgICAgICAgc2Y6OkNvbG9yIGM7CgogICAgICAgICAgICBmb3IgKGludCB4ID0gLXNpemU7IHggPD0gc2l6ZTsgKysgeCkgewogICAgICAgICAgICAgICAgZm9yIChpbnQgeSA9IC1zaXplOyB5IDw9IHNpemU7ICsrIHkpIHsKCiAgICAgICAgICAgICAgICAgICAgaW50IGEgPSAoKHggKyBpKSAlIHdpZHRoICsgd2lkdGgpICUgd2lkdGg7CiAgICAgICAgICAgICAgICAgICAgaW50IGIgPSAoKHkgKyBqKSAlIGhlaWdodCArIGhlaWdodCkgJSBoZWlnaHQ7CgogICAgICAgICAgICAgICAgICAgIGMgPSBpbWFnZTIuR2V0UGl4ZWwoYSwgYik7CgogICAgICAgICAgICAgICAgICAgIHJzLnB1c2hfYmFjayhjLnIpOwogICAgICAgICAgICAgICAgICAgIGdzLnB1c2hfYmFjayhjLmcpOwogICAgICAgICAgICAgICAgICAgIGJzLnB1c2hfYmFjayhjLmIpOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CgogICAgICAgICAgICBjID0gaW1hZ2UyLkdldFBpeGVsKGksIGopOwoKICAgICAgICAgICAgaWYgKHJlZCkgewogICAgICAgICAgICAgICAgc3RkOjpzb3J0KHJzLmJlZ2luKCksIHJzLmVuZCgpKTsKICAgICAgICAgICAgICAgIGMuciA9IHJzW3JzLnNpemUoKSAvIDJdOwogICAgICAgICAgICB9CgogICAgICAgICAgICBpZiAoZ3JlZW4pIHsKICAgICAgICAgICAgICAgIHN0ZDo6c29ydChncy5iZWdpbigpLCBncy5lbmQoKSk7CiAgICAgICAgICAgICAgICBjLmcgPSBnc1tncy5zaXplKCkgLyAyXTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKGJsdWUpIHsKICAgICAgICAgICAgICAgIHN0ZDo6c29ydChicy5iZWdpbigpLCBicy5lbmQoKSk7CiAgICAgICAgICAgICAgICBjLmIgPSBic1ticy5zaXplKCkgLyAyXTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaW1hZ2UuU2V0UGl4ZWwoaSwgaiwgYyk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIGJsZW5kKHNmOjpJbWFnZSAmIGRlc3QsIHNmOjpJbWFnZSBzb3VyY2UxLCBzZjo6SW1hZ2Ugc291cmNlMiwgaW50IHcxLCBpbnQgdzIpIHsKCiAgICBjb25zdCBpbnQgd2lkdGggPSBkZXN0LkdldFdpZHRoKCk7CiAgICBjb25zdCBpbnQgaGVpZ2h0ID0gZGVzdC5HZXRIZWlnaHQoKTsKCiAgICBmb3IgKGludCBpID0gMDsgaSA8IHdpZHRoOyArKyBpKSB7CiAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBoZWlnaHQ7ICsrIGopIHsKCiAgICAgICAgICAgIGludCByID0gMCwgZyA9IDAsIGIgPSAwOwoKICAgICAgICAgICAgc2Y6OkNvbG9yIHAxID0gc291cmNlMS5HZXRQaXhlbChpLCBqKTsKICAgICAgICAgICAgc2Y6OkNvbG9yIHAyID0gc291cmNlMi5HZXRQaXhlbChpLCBqKTsKCiAgICAgICAgICAgIHIgKz0gdzEgKiBwMS5yOwogICAgICAgICAgICByICs9IHcyICogcDIucjsKCiAgICAgICAgICAgIGcgKz0gdzEgKiBwMS5nOwogICAgICAgICAgICBnICs9IHcyICogcDIuZzsKCiAgICAgICAgICAgIGIgKz0gdzEgKiBwMS5iOwogICAgICAgICAgICBiICs9IHcyICogcDIuYjsKCiAgICAgICAgICAgIHIgLz0gKHcxICsgdzIpOwogICAgICAgICAgICBnIC89ICh3MSArIHcyKTsKICAgICAgICAgICAgYiAvPSAodzEgKyB3Mik7CgogICAgICAgICAgICBkZXN0LlNldFBpeGVsKGksIGosIHNmOjpDb2xvcihyLCBnLCBiKSk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIHBpeGVsaXplKHNmOjpJbWFnZSAmIGltYWdlLCBpbnQgc2l6ZSkgewoKICAgIGNvbnN0IGludCB3aWR0aCA9IGltYWdlLkdldFdpZHRoKCk7CiAgICBjb25zdCBpbnQgaGVpZ2h0ID0gaW1hZ2UuR2V0SGVpZ2h0KCk7CgogICAgc2Y6OkltYWdlIGltYWdlMihpbWFnZSk7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCB3aWR0aDsgaSArPSBzaXplKSB7CiAgICAgICAgZm9yIChpbnQgaiA9IDA7IGogPCBoZWlnaHQ7IGogKz0gc2l6ZSkgewoKICAgICAgICAgICAgc2Y6OkNvbG9yIGN1ckNvbG9yID0gaW1hZ2UyLkdldFBpeGVsKGksIGopOwoKICAgICAgICAgICAgZm9yIChpbnQgeCA9IDA7IHggPCBzaXplOyArKyB4KSB7CiAgICAgICAgICAgICAgICBmb3IgKGludCB5ID0gMDsgeSA8IHNpemU7ICsrIHkpIHsKCiAgICAgICAgICAgICAgICAgICAgaW50IGEgPSAoKHggKyBpKSAlIHdpZHRoICsgd2lkdGgpICUgd2lkdGg7CiAgICAgICAgICAgICAgICAgICAgaW50IGIgPSAoKHkgKyBqKSAlIGhlaWdodCArIGhlaWdodCkgJSBoZWlnaHQ7CgogICAgICAgICAgICAgICAgICAgIGltYWdlLlNldFBpeGVsKGEsIGIsIGN1ckNvbG9yKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KfQoKdm9pZCBtYWduaWZ5aW5nRHJvcHMoc2Y6OkltYWdlICYgaW1hZ2UsIGludCBjb3VudCwgaW50IG1pblNpemUsIGludCBtYXhTaXplLCBkb3VibGUgZXhwb25lbnQpIHsKCiAgICBjb25zdCBpbnQgd2lkdGggPSBpbWFnZS5HZXRXaWR0aCgpOwogICAgY29uc3QgaW50IGhlaWdodCA9IGltYWdlLkdldEhlaWdodCgpOwoKICAgIHNmOjpJbWFnZSBpbWFnZTIoaW1hZ2UpOwoKICAgICBmb3IgKGludCBpID0gMDsgaSA8IGNvdW50OyArKyBpKSB7CgogICAgICAgIGludCBjeCA9IHN0ZDo6cmFuZCgpICUgd2lkdGg7CiAgICAgICAgaW50IGN5ID0gc3RkOjpyYW5kKCkgJSBoZWlnaHQ7CgogICAgICAgIGludCBzaXplID0gc3RkOjpyYW5kKCkgJSAobWF4U2l6ZSAtIG1pblNpemUgKyAxKSArIG1pblNpemU7CgogICAgICAgIGludCBzMiA9IHNpemUgKiBzaXplOwoKICAgICAgICBkb3VibGUgbSA9IHN0ZDo6cG93KHNpemUsIDEgLSBleHBvbmVudCk7CgogICAgICAgIGZvciAoaW50IHggPSAtIHNpemU7IHggPD0gc2l6ZTsgKysgeCkgewogICAgICAgICAgICBmb3IgKGludCB5ID0gLSBzaXplOyB5IDw9IHNpemU7ICsrIHkpIHsKCiAgICAgICAgICAgICAgICBpbnQgc2lnbnggPSB4IDwgMCA/IC0xIDogMTsKICAgICAgICAgICAgICAgIGludCBzaWdueSA9IHkgPCAwID8gLTEgOiAxOwoKICAgICAgICAgICAgICAgIGludCBkMiA9IHggKiB4ICsgeSAqIHk7CgogICAgICAgICAgICAgICAgaWYgKGQyID4gczIpIGNvbnRpbnVlOwoKICAgICAgICAgICAgICAgIGludCBzeCA9IChpbnQoY3ggKyBzaWdueCAqIHN0ZDo6cG93KHNpZ254ICogeCwgZXhwb25lbnQpICogbSkgJSB3aWR0aCArIHdpZHRoKSAlIHdpZHRoOwogICAgICAgICAgICAgICAgaW50IHN5ID0gKGludChjeSArIHNpZ255ICogc3RkOjpwb3coc2lnbnkgKiB5LCBleHBvbmVudCkgKiBtKSAlIGhlaWdodCArIGhlaWdodCkgJSBoZWlnaHQ7CgogICAgICAgICAgICAgICAgaW50IHR4ID0gKChjeCArIHgpICUgd2lkdGggKyB3aWR0aCkgJSB3aWR0aDsKICAgICAgICAgICAgICAgIGludCB0eSA9ICgoY3kgKyB5KSAlIGhlaWdodCArIGhlaWdodCkgJSBoZWlnaHQ7CgogICAgICAgICAgICAgICAgaW1hZ2UuU2V0UGl4ZWwodHgsIHR5LCBpbWFnZTIuR2V0UGl4ZWwoc3gsIHN5KSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgfQp9CgppbnQgbWFpbigpCnsKICAgIHN0ZDo6c3JhbmQoc3RkOjp0aW1lKDApKTsKCiAgICBjb25zdCBpbnQgd2lkdGggID0gNTEyOwogICAgY29uc3QgaW50IGhlaWdodCA9IDI1NjsKCiAgICBzZjo6SW1hZ2UgdHh0X2JpdCh3aWR0aCwgaGVpZ2h0LCBzZjo6Q29sb3I6OkJsYWNrKTsKICAgIHNmOjpJbWFnZSB0eHRfd2FsbCh3aWR0aCwgaGVpZ2h0LCBzZjo6Q29sb3I6OkJsYWNrKTsKICAgIHNmOjpJbWFnZSB0eHRfbm9pc2Uod2lkdGgsIGhlaWdodCwgc2Y6OkNvbG9yOjpCbGFjayk7CiAgICBzZjo6SW1hZ2UgdHh0X2Ryb3BzKHdpZHRoLCBoZWlnaHQsIHNmOjpDb2xvcjo6QmxhY2spOwogICAgc2Y6OkltYWdlIHR4dF9yZXN1bHQod2lkdGgsIGhlaWdodCwgc2Y6OkNvbG9yOjpCbGFjayk7CgogICAgdHh0X2JpdC5TZXRTbW9vdGgoZmFsc2UpOwogICAgdHh0X3dhbGwuU2V0U21vb3RoKGZhbHNlKTsKICAgIHR4dF9ub2lzZS5TZXRTbW9vdGgoZmFsc2UpOwogICAgdHh0X2Ryb3BzLlNldFNtb290aChmYWxzZSk7CiAgICB0eHRfcmVzdWx0LlNldFNtb290aChmYWxzZSk7CgogICAgLyoKICAgIGJpdCh0eHRfYml0LCAxNiwgNjQsIDMyKTsKICAgIG1lZGlhbih0eHRfYml0LCAyKTsKICAgIC8vKi8KCiAgICAvKgogICAgYml0KHR4dF9iaXQsIDMyLCA2NCwgMTYpOwogICAgbWVkaWFuKHR4dF9iaXQsIDIpOwogICAgLy8qLwoKICAgIC8qCiAgICBiaXQodHh0X2JpdCwgNjQsIDMyLCAxNik7CiAgICBtZWRpYW4odHh0X2JpdCwgMik7CiAgICAvLyovCgogICAgLyoKICAgIGJpdCh0eHRfYml0LCA0LCA4LCAxNik7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICAvLyovCgogICAgLyoKICAgIGJpdCh0eHRfYml0LCAxNiwgOCwgMTYpOwogICAgbWVkaWFuKHR4dF9iaXQsIDEpOwogICAgbWVkaWFuKHR4dF9iaXQsIDEpOwogICAgLy8qLwoKICAgIC8qCiAgICBiaXQodHh0X2JpdCwgMTUsIDE2LCAxNyk7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICAvLyovCgogICAgLy8vKgogICAgYml0KHR4dF9iaXQsIDM1LCA3MCwgMTQwKTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIG1lZGlhbih0eHRfYml0LCAyKTsKICAgIC8vKi8KCiAgICB3YWxsKHR4dF93YWxsLCB0cnVlKTsKICAgIG5vaXNlKHR4dF9ub2lzZSk7CiAgICB3aGl0ZURyb3BzKHR4dF9kcm9wcywgMjUwLCA0MCwgODAsIGZhbHNlLCAxMjUpOwogICAgYmxlbmQodHh0X3Jlc3VsdCwgdHh0X2Ryb3BzLCB0eHRfbm9pc2UsIDE1LCA1KTsKICAgIG1lZGlhbih0eHRfcmVzdWx0LCAxKTsKICAgIGJsZW5kKHR4dF9yZXN1bHQsIHR4dF93YWxsLCB0eHRfcmVzdWx0LCAxMywgMik7CiAgICBtYWduaWZ5aW5nRHJvcHModHh0X3Jlc3VsdCwgMTAsIDQwLCA1MCwgMS4xNSk7CiAgICBwaXhlbGl6ZSh0eHRfcmVzdWx0LCA0KTsKCiAgICBzZjo6U3ByaXRlIHNwcml0ZSh0eHRfcmVzdWx0KTsKCiAgICAvL3BpeGVsaXplKHR4dF9iaXQsIDIpOwogICAgLy9zZjo6U3ByaXRlIHNwcml0ZSh0eHRfYml0KTsKCiAgICBzZjo6UmVuZGVyV2luZG93IHdpbmRvdyhzZjo6VmlkZW9Nb2RlKHdpZHRoICogMiwgaGVpZ2h0ICogMiwgMzIpLCAiUHJvY2VkdXJhbCBUZXh0dXJlcyEiKTsKCiAgICB3aW5kb3cuVXNlVmVydGljYWxTeW5jKHRydWUpOwoKICAgIGJvb2wgUnVubmluZyA9IHRydWU7CgogICAgd2hpbGUgKFJ1bm5pbmcpCiAgICB7CiAgICAgICAgc2Y6OkV2ZW50IEV2ZW50OwoKICAgICAgICB3aGlsZSAod2luZG93LkdldEV2ZW50KEV2ZW50KSkKICAgICAgICB7CiAgICAgICAgICAgIGlmIChFdmVudC5UeXBlID09IHNmOjpFdmVudDo6Q2xvc2VkKQogICAgICAgICAgICAgICAgUnVubmluZyA9IGZhbHNlOwoKICAgICAgICAgICAgaWYgKChFdmVudC5UeXBlID09IHNmOjpFdmVudDo6S2V5UHJlc3NlZCkgJiYgKEV2ZW50LktleS5Db2RlID09IHNmOjpLZXk6OkVzY2FwZSkpCiAgICAgICAgICAgICAgICBSdW5uaW5nID0gZmFsc2U7CiAgICAgICAgfQoKICAgICAgICB3aW5kb3cuQ2xlYXIoKTsKCiAgICAgICAgd2luZG93LkRyYXcoc3ByaXRlKTsKICAgICAgICBzcHJpdGUuTW92ZSh3aWR0aCwgMCk7CiAgICAgICAgd2luZG93LkRyYXcoc3ByaXRlKTsKICAgICAgICBzcHJpdGUuTW92ZSgwLCBoZWlnaHQpOwogICAgICAgIHdpbmRvdy5EcmF3KHNwcml0ZSk7CiAgICAgICAgc3ByaXRlLk1vdmUoLSB3aWR0aCwgMCk7CiAgICAgICAgd2luZG93LkRyYXcoc3ByaXRlKTsKICAgICAgICBzcHJpdGUuTW92ZSgwLCAtIGhlaWdodCk7CgogICAgICAgIHdpbmRvdy5EaXNwbGF5KCk7CiAgICB9Cn0=