#include <SFML/Graphics.hpp>
#include <algorithm>
#include <vector>
#include <map>
#include <cstdlib>
#include <ctime>
#include <cmath>
void noise(sf::Image & image) {
sf::Vector2u imageSize = image.getSize() ;
for (unsigned i = 0; i < imageSize.x; ++ i) {
for (unsigned j = 0; j < imageSize.y; ++ 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 sf::Vector2u imageSize = image.getSize() ;
for (unsigned i = 0; i < imageSize.x ; ++ i) {
for (unsigned j = 0; j < imageSize.y; ++ 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) {
unsigned x = (i + offset) / 128;
unsigned y = j / 64;
if (x >= imageSize.x / 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 sf::Vector2u imageSize = image.getSize() ;
for (int i = 0; i < count; ++ i) {
int cx = std::rand() % imageSize.x;
int cy = std::rand() % imageSize.y;
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 % imageSize.x + imageSize.x) % imageSize.x;
int py = (y % imageSize.y + imageSize.y) % imageSize.y;
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 sf::Vector2u imageSize = image.getSize() ;
for (unsigned i = 0; i < imageSize.x; ++ i) {
for (unsigned j = 0; j < imageSize.y; ++ 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 sf::Vector2u imageSize = image.getSize() ;
for (unsigned i = 0; i < imageSize.x; ++ i) {
for (unsigned j = 0; j < imageSize.y; ++ 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) % imageSize.x + imageSize.x) % imageSize.x;
int b = ((y + j) % imageSize.y + imageSize.y) % imageSize.y;
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 sf::Vector2u destSize = dest.getSize() ;
for (unsigned i = 0; i < destSize.x ; ++ i) {
for (unsigned j = 0; j < destSize.y ; ++ 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 sf::Vector2u imageSize = image.getSize() ;
sf::Image image2(image);
for (unsigned i = 0; i < imageSize.x; i += size) {
for (unsigned j = 0; j < imageSize.y; 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) % imageSize.x + imageSize.x) % imageSize.x;
int b = ((y + j) % imageSize.y + imageSize.y) % imageSize.y;
image.setPixel(a, b, curColor);
}
}
}
}
}
void magnifyingDrops(sf::Image & image, int count, int minSize, int maxSize, double exponent) {
const sf::Vector2u imageSize = image.getSize() ;
sf::Image image2(image);
for (int i = 0; i < count; ++ i) {
int cx = std::rand() % imageSize.x;
int cy = std::rand() % imageSize.y;
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) % imageSize.x + imageSize.x) % imageSize.x;
int sy = (int(cy + signy * std::pow(signy * y, exponent) * m) % imageSize.y + imageSize.y) % imageSize.y;
int tx = ((cx + x) % imageSize.x + imageSize.x) % imageSize.x;
int ty = ((cy + y) % imageSize.y + imageSize.y) % imageSize.y;
image.setPixel(tx, ty, image2.getPixel(sx, sy));
}
}
}
}
int main()
{
std::srand(static_cast<unsigned>(std::time(0)));
const int width = 512;
const int height = 256;
sf::Image txt_bit;
sf::Image txt_wall;
sf::Image txt_noise;
sf::Image txt_drops;
sf::Image txt_result;
txt_bit.create(width, height, sf::Color::Black) ;
txt_wall.create(width, height, sf::Color::Black) ;
txt_noise.create(width, height, sf::Color::Black) ;
txt_drops.create(width, height, sf::Color::Black) ;
txt_result.create(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::Texture resultTexture ;
resultTexture.loadFromImage(txt_result) ;
resultTexture.setSmooth(true) ;
sf::Sprite sprite(resultTexture);
//pixelize(txt_bit, 2);
//sf::Sprite sprite(txt_bit);
sf::RenderWindow window(sf::VideoMode(width * 2, height * 2, 32), "Procedural Textures!");
window.setVerticalSyncEnabled(true);
bool Running = true;
while (Running)
{
sf::Event Event;
while (window.pollEvent(Event))
{
if (Event.type == sf::Event::Closed)
Running = false;
if ((Event.type == sf::Event::KeyPressed) && (Event.key.code == sf::Keyboard::Escape))
Running = false;
}
window.clear();
window.draw(sprite);
sprite.move(static_cast<float>(width), 0.0f);
window.draw(sprite);
sprite.move(0.0f, static_cast<float>(height));
window.draw(sprite);
sprite.move(static_cast<float>(- width), 0.0f);
window.draw(sprite);
sprite.move(0.0f, static_cast<float>(- height));
window.display();
}
}
I2luY2x1ZGUgPFNGTUwvR3JhcGhpY3MuaHBwPgojaW5jbHVkZSA8YWxnb3JpdGhtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8bWFwPgojaW5jbHVkZSA8Y3N0ZGxpYj4KI2luY2x1ZGUgPGN0aW1lPgojaW5jbHVkZSA8Y21hdGg+Cgp2b2lkIG5vaXNlKHNmOjpJbWFnZSAmIGltYWdlKSB7CgogICAgc2Y6OlZlY3RvcjJ1IGltYWdlU2l6ZSA9IGltYWdlLmdldFNpemUoKSA7CgogICAgZm9yICh1bnNpZ25lZCBpID0gMDsgaSA8IGltYWdlU2l6ZS54OyArKyBpKSB7CiAgICAgICAgZm9yICh1bnNpZ25lZCBqID0gMDsgaiA8IGltYWdlU2l6ZS55OyArKyBqKSB7CgogICAgICAgICAgICBpbnQgdmFsID0gc3RkOjpyYW5kKCkgJSAyNTY7CgogICAgICAgICAgICBpbWFnZS5zZXRQaXhlbChpLCBqLCBzZjo6Q29sb3IodmFsLCB2YWwsIHZhbCkpOwogICAgICAgIH0KICAgIH0KfQoKdm9pZCB3YWxsKHNmOjpJbWFnZSAmIGltYWdlLCBib29sIGNvb2wpIHsKCiAgICBzdGQ6Om1hcDxpbnQsIGludD4gaW50ZXJpb3JJZDJvZmZzZXQ7CgogICAgY29uc3Qgc2Y6OlZlY3RvcjJ1IGltYWdlU2l6ZSA9IGltYWdlLmdldFNpemUoKSA7CgogICAgZm9yICh1bnNpZ25lZCBpID0gMDsgaSA8IGltYWdlU2l6ZS54IDsgKysgaSkgewogICAgICAgIGZvciAodW5zaWduZWQgaiA9IDA7IGogPCBpbWFnZVNpemUueTsgKysgaikgewoKICAgICAgICAgICAgaW50IHZhbCA9IDA7CiAgICAgICAgICAgIGludCBvZmZzZXQgPSAwOwoKICAgICAgICAgICAgaWYgKGogJSAxMjggPCA2NCkgb2Zmc2V0ID0gNDA7CgogICAgICAgICAgICBib29sIG9uZSA9ICgoaSArIG9mZnNldCkgJSAxMjggPCAyIHx8IChpICsgb2Zmc2V0KSAlIDEyOCA+IDEyNik7CiAgICAgICAgICAgIGJvb2wgdHdvID0gKCBqICAgICAgICAgICAlICA2NCA8IDIgfHwgIGogICAgICAgICAgICUgIDY0ID4gIDYyKTsKCiAgICAgICAgICAgIGJvb2wgbmVhck9uZSA9IChpICUgMTI4IDwgOCB8fCBpICUgMTI4ID4gMTIwKTsKICAgICAgICAgICAgYm9vbCBuZWFyVHdvID0gKGogJSAgNjQgPCA4IHx8IGogJSAgNjQgPiAgNTYpOwoKICAgICAgICAgICAgaWYgKG9uZSAmJiAhbmVhclR3byB8fCB0d28gJiYgIW5lYXJPbmUpIHZhbCA9IDIyNTsKCiAgICAgICAgICAgIGJvb2wgaW50ZXJpb3IgPSAhb25lICYmICF0d287CgogICAgICAgICAgICBpZiAoaW50ZXJpb3IpIHsKCiAgICAgICAgICAgICAgICB1bnNpZ25lZCB4ID0gKGkgKyBvZmZzZXQpIC8gMTI4OwogICAgICAgICAgICAgICAgdW5zaWduZWQgeSA9ICBqICAgICAgICAgICAvICA2NDsKCiAgICAgICAgICAgICAgICBpZiAoeCA+PSBpbWFnZVNpemUueCAvIDEyOCkgeCA9IDA7IC8vIGluIG9yZGVyIHRvIGJlIHRpbGVhYmxlCgogICAgICAgICAgICAgICAgaW50IGludGVyaW9yT2Zmc2V0ID0gaW50ZXJpb3JJZDJvZmZzZXRbeCArIDEwMCAqIHldOwoKICAgICAgICAgICAgICAgIGlmIChpbnRlcmlvck9mZnNldCA9PSAwKSB7CgogICAgICAgICAgICAgICAgICAgIGludGVyaW9yT2Zmc2V0ID0gc3RkOjpyYW5kKCkgJSAzICogMzAgKyAxOwogICAgICAgICAgICAgICAgICAgIGludGVyaW9ySWQyb2Zmc2V0W3ggKyAxMDAgKiB5XSA9IGludGVyaW9yT2Zmc2V0OwogICAgICAgICAgICAgICAgfQoKICAgICAgICAgICAgICAgIHZhbCA9ICgoaSArIG9mZnNldCkgJSAxMjggKyBqICUgNjQgKyBpbnRlcmlvck9mZnNldCkgJSAyNTY7CgogICAgICAgICAgICAgICAgaWYgKHZhbCA8ICAyNSkgdmFsID0gIDI1OwogICAgICAgICAgICAgICAgaWYgKHZhbCA+IDE3NSkgdmFsID0gMTc1OwogICAgICAgICAgICB9CgogICAgICAgICAgICBpZiAoY29vbCkgdmFsID0gKHZhbCArIHN0ZDo6cmFuZCgpICUgMTUgKyAzNSkgJSAyNTY7CgogICAgICAgICAgICBpbWFnZS5zZXRQaXhlbChpLCBqLCBzZjo6Q29sb3IodmFsLCB2YWwsIHZhbCkpOwogICAgICAgIH0KICAgIH0KfQoKdm9pZCB3aGl0ZURyb3BzKHNmOjpJbWFnZSAmIGltYWdlLCBpbnQgY291bnQsIGludCBtaW5TaXplLCBpbnQgbWF4U2l6ZSwgYm9vbCBmaWxsZWQgPSB0cnVlLCBpbnQgdGhpY2tuZXNzID0gMCkgewoKICAgIGNvbnN0IHNmOjpWZWN0b3IydSBpbWFnZVNpemUgPSBpbWFnZS5nZXRTaXplKCkgOwoKICAgIGZvciAoaW50IGkgPSAwOyBpIDwgY291bnQ7ICsrIGkpIHsKCiAgICAgICAgaW50IGN4ID0gc3RkOjpyYW5kKCkgJSBpbWFnZVNpemUueDsKICAgICAgICBpbnQgY3kgPSBzdGQ6OnJhbmQoKSAlIGltYWdlU2l6ZS55OwoKICAgICAgICBpbnQgc2l6ZSA9IHN0ZDo6cmFuZCgpICUgKG1heFNpemUgLSBtaW5TaXplICsgMSkgKyBtaW5TaXplOwoKICAgICAgICBmb3IgKGludCB4ID0gY3ggLSBzaXplOyB4IDw9IGN4ICsgc2l6ZTsgKysgeCkgewogICAgICAgICAgICBmb3IgKGludCB5ID0gY3kgLSBzaXplOyB5IDw9IGN5ICsgc2l6ZTsgKysgeSkgewoKICAgICAgICAgICAgICAgIGludCBkMiA9ICh4IC0gY3gpICogKHggLSBjeCkgKyAoeSAtIGN5KSAqICh5IC0gY3kpOwogICAgICAgICAgICAgICAgaW50IHMyID0gc2l6ZSAqIHNpemU7CgogICAgICAgICAgICAgICAgaWYgKGQyIDw9IHMyKSB7CgogICAgICAgICAgICAgICAgICAgIGludCBweCA9ICh4ICUgaW1hZ2VTaXplLnggKyBpbWFnZVNpemUueCkgJSBpbWFnZVNpemUueDsKICAgICAgICAgICAgICAgICAgICBpbnQgcHkgPSAoeSAlIGltYWdlU2l6ZS55ICsgaW1hZ2VTaXplLnkpICUgaW1hZ2VTaXplLnk7CgogICAgICAgICAgICAgICAgICAgIGlmIChkMiA8PSBzMiAtIHRoaWNrbmVzcykgewogICAgICAgICAgICAgICAgICAgICAgICBpZiAoZmlsbGVkKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2Uuc2V0UGl4ZWwocHgsIHB5LCBzZjo6Q29sb3I6OkJsYWNrKTsKICAgICAgICAgICAgICAgICAgICB9IGVsc2UgewogICAgICAgICAgICAgICAgICAgICAgICBpbWFnZS5zZXRQaXhlbChweCwgcHksIHNmOjpDb2xvcjo6V2hpdGUpOwogICAgICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KfQoKdm9pZCBiaXQoc2Y6OkltYWdlICYgaW1hZ2UsIGludCBhLCBpbnQgYiwgaW50IGMpIHsKCiAgICBjb25zdCBzZjo6VmVjdG9yMnUgaW1hZ2VTaXplID0gaW1hZ2UuZ2V0U2l6ZSgpIDsKCiAgICBmb3IgKHVuc2lnbmVkIGkgPSAwOyBpIDwgaW1hZ2VTaXplLng7ICsrIGkpIHsKICAgICAgICBmb3IgKHVuc2lnbmVkIGogPSAwOyBqIDwgaW1hZ2VTaXplLnk7ICsrIGopIHsKCiAgICAgICAgICAgIGludCB2YWwgPSAoYSAqIChpICYgaikgKyBiICogKGkgXiBqKSArIGMgKiAoaSB8IGopKSAlIDI1NjsKCiAgICAgICAgICAgIGltYWdlLnNldFBpeGVsKGksIGosIHNmOjpDb2xvcih2YWwsIHZhbCwgdmFsKSk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIG1lZGlhbihzZjo6SW1hZ2UgJiBpbWFnZSwgaW50IHNpemUsIGJvb2wgcmVkID0gdHJ1ZSwgYm9vbCBncmVlbiA9IHRydWUsIGJvb2wgYmx1ZSA9IHRydWUpIHsKCiAgICBzZjo6SW1hZ2UgaW1hZ2UyKGltYWdlKTsKCiAgICBjb25zdCBzZjo6VmVjdG9yMnUgaW1hZ2VTaXplID0gaW1hZ2UuZ2V0U2l6ZSgpIDsKCiAgICBmb3IgKHVuc2lnbmVkIGkgPSAwOyBpIDwgaW1hZ2VTaXplLng7ICsrIGkpIHsKICAgICAgICBmb3IgKHVuc2lnbmVkIGogPSAwOyBqIDwgaW1hZ2VTaXplLnk7ICsrIGopIHsKCiAgICAgICAgICAgIHN0ZDo6dmVjdG9yPGludD4gcnMsIGdzLCBiczsKCiAgICAgICAgICAgIHNmOjpDb2xvciBjOwoKICAgICAgICAgICAgZm9yIChpbnQgeCA9IC1zaXplOyB4IDw9IHNpemU7ICsrIHgpIHsKICAgICAgICAgICAgICAgIGZvciAoaW50IHkgPSAtc2l6ZTsgeSA8PSBzaXplOyArKyB5KSB7CgogICAgICAgICAgICAgICAgICAgIGludCBhID0gKCh4ICsgaSkgJSBpbWFnZVNpemUueCArIGltYWdlU2l6ZS54KSAlIGltYWdlU2l6ZS54OwogICAgICAgICAgICAgICAgICAgIGludCBiID0gKCh5ICsgaikgJSBpbWFnZVNpemUueSArIGltYWdlU2l6ZS55KSAlIGltYWdlU2l6ZS55OwoKICAgICAgICAgICAgICAgICAgICBjID0gaW1hZ2UyLmdldFBpeGVsKGEsIGIpOwoKICAgICAgICAgICAgICAgICAgICBycy5wdXNoX2JhY2soYy5yKTsKICAgICAgICAgICAgICAgICAgICBncy5wdXNoX2JhY2soYy5nKTsKICAgICAgICAgICAgICAgICAgICBicy5wdXNoX2JhY2soYy5iKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQoKICAgICAgICAgICAgYyA9IGltYWdlMi5nZXRQaXhlbChpLCBqKTsKCiAgICAgICAgICAgIGlmIChyZWQpIHsKICAgICAgICAgICAgICAgIHN0ZDo6c29ydChycy5iZWdpbigpLCBycy5lbmQoKSk7CiAgICAgICAgICAgICAgICBjLnIgPSByc1tycy5zaXplKCkgLyAyXTsKICAgICAgICAgICAgfQoKICAgICAgICAgICAgaWYgKGdyZWVuKSB7CiAgICAgICAgICAgICAgICBzdGQ6OnNvcnQoZ3MuYmVnaW4oKSwgZ3MuZW5kKCkpOwogICAgICAgICAgICAgICAgYy5nID0gZ3NbZ3Muc2l6ZSgpIC8gMl07CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGlmIChibHVlKSB7CiAgICAgICAgICAgICAgICBzdGQ6OnNvcnQoYnMuYmVnaW4oKSwgYnMuZW5kKCkpOwogICAgICAgICAgICAgICAgYy5iID0gYnNbYnMuc2l6ZSgpIC8gMl07CiAgICAgICAgICAgIH0KCiAgICAgICAgICAgIGltYWdlLnNldFBpeGVsKGksIGosIGMpOwogICAgICAgIH0KICAgIH0KfQoKdm9pZCBibGVuZChzZjo6SW1hZ2UgJiBkZXN0LCBzZjo6SW1hZ2Ugc291cmNlMSwgc2Y6OkltYWdlIHNvdXJjZTIsIGludCB3MSwgaW50IHcyKSB7CgogICAgY29uc3Qgc2Y6OlZlY3RvcjJ1IGRlc3RTaXplID0gZGVzdC5nZXRTaXplKCkgOwogCiAgICBmb3IgKHVuc2lnbmVkIGkgPSAwOyBpIDwgZGVzdFNpemUueCA7ICsrIGkpIHsKICAgICAgICBmb3IgKHVuc2lnbmVkIGogPSAwOyBqIDwgZGVzdFNpemUueSA7ICsrIGopIHsKCiAgICAgICAgICAgIGludCByID0gMCwgZyA9IDAsIGIgPSAwOwoKICAgICAgICAgICAgc2Y6OkNvbG9yIHAxID0gc291cmNlMS5nZXRQaXhlbChpLCBqKTsKICAgICAgICAgICAgc2Y6OkNvbG9yIHAyID0gc291cmNlMi5nZXRQaXhlbChpLCBqKTsKCiAgICAgICAgICAgIHIgKz0gdzEgKiBwMS5yOwogICAgICAgICAgICByICs9IHcyICogcDIucjsKCiAgICAgICAgICAgIGcgKz0gdzEgKiBwMS5nOwogICAgICAgICAgICBnICs9IHcyICogcDIuZzsKCiAgICAgICAgICAgIGIgKz0gdzEgKiBwMS5iOwogICAgICAgICAgICBiICs9IHcyICogcDIuYjsKCiAgICAgICAgICAgIHIgLz0gKHcxICsgdzIpOwogICAgICAgICAgICBnIC89ICh3MSArIHcyKTsKICAgICAgICAgICAgYiAvPSAodzEgKyB3Mik7CgogICAgICAgICAgICBkZXN0LnNldFBpeGVsKGksIGosIHNmOjpDb2xvcihyLCBnLCBiKSk7CiAgICAgICAgfQogICAgfQp9Cgp2b2lkIHBpeGVsaXplKHNmOjpJbWFnZSAmIGltYWdlLCBpbnQgc2l6ZSkgewoKICAgIGNvbnN0IHNmOjpWZWN0b3IydSBpbWFnZVNpemUgPSBpbWFnZS5nZXRTaXplKCkgOwoKICAgIHNmOjpJbWFnZSBpbWFnZTIoaW1hZ2UpOwoKICAgIGZvciAodW5zaWduZWQgaSA9IDA7IGkgPCBpbWFnZVNpemUueDsgaSArPSBzaXplKSB7CiAgICAgICAgZm9yICh1bnNpZ25lZCBqID0gMDsgaiA8IGltYWdlU2l6ZS55OyBqICs9IHNpemUpIHsKCiAgICAgICAgICAgIHNmOjpDb2xvciBjdXJDb2xvciA9IGltYWdlMi5nZXRQaXhlbChpLCBqKTsKCiAgICAgICAgICAgIGZvciAoaW50IHggPSAwOyB4IDwgc2l6ZTsgKysgeCkgewogICAgICAgICAgICAgICAgZm9yIChpbnQgeSA9IDA7IHkgPCBzaXplOyArKyB5KSB7CgogICAgICAgICAgICAgICAgICAgIGludCBhID0gKCh4ICsgaSkgJSBpbWFnZVNpemUueCArIGltYWdlU2l6ZS54KSAlIGltYWdlU2l6ZS54OwogICAgICAgICAgICAgICAgICAgIGludCBiID0gKCh5ICsgaikgJSBpbWFnZVNpemUueSArIGltYWdlU2l6ZS55KSAlIGltYWdlU2l6ZS55OwoKICAgICAgICAgICAgICAgICAgICBpbWFnZS5zZXRQaXhlbChhLCBiLCBjdXJDb2xvcik7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KCnZvaWQgbWFnbmlmeWluZ0Ryb3BzKHNmOjpJbWFnZSAmIGltYWdlLCBpbnQgY291bnQsIGludCBtaW5TaXplLCBpbnQgbWF4U2l6ZSwgZG91YmxlIGV4cG9uZW50KSB7CgogICAgY29uc3Qgc2Y6OlZlY3RvcjJ1IGltYWdlU2l6ZSA9IGltYWdlLmdldFNpemUoKSA7CgogICAgc2Y6OkltYWdlIGltYWdlMihpbWFnZSk7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBjb3VudDsgKysgaSkgewoKICAgICAgICBpbnQgY3ggPSBzdGQ6OnJhbmQoKSAlIGltYWdlU2l6ZS54OwogICAgICAgIGludCBjeSA9IHN0ZDo6cmFuZCgpICUgaW1hZ2VTaXplLnk7CgogICAgICAgIGludCBzaXplID0gc3RkOjpyYW5kKCkgJSAobWF4U2l6ZSAtIG1pblNpemUgKyAxKSArIG1pblNpemU7CgogICAgICAgIGludCBzMiA9IHNpemUgKiBzaXplOwoKICAgICAgICBkb3VibGUgbSA9IHN0ZDo6cG93KHNpemUsIDEgLSBleHBvbmVudCk7CgogICAgICAgIGZvciAoaW50IHggPSAtIHNpemU7IHggPD0gc2l6ZTsgKysgeCkgewogICAgICAgICAgICBmb3IgKGludCB5ID0gLSBzaXplOyB5IDw9IHNpemU7ICsrIHkpIHsKCiAgICAgICAgICAgICAgICBpbnQgc2lnbnggPSB4IDwgMCA/IC0xIDogMTsKICAgICAgICAgICAgICAgIGludCBzaWdueSA9IHkgPCAwID8gLTEgOiAxOwoKICAgICAgICAgICAgICAgIGludCBkMiA9IHggKiB4ICsgeSAqIHk7CgogICAgICAgICAgICAgICAgaWYgKGQyID4gczIpIGNvbnRpbnVlOwoKICAgICAgICAgICAgICAgIGludCBzeCA9IChpbnQoY3ggKyBzaWdueCAqIHN0ZDo6cG93KHNpZ254ICogeCwgZXhwb25lbnQpICogbSkgJSBpbWFnZVNpemUueCArIGltYWdlU2l6ZS54KSAlIGltYWdlU2l6ZS54OwogICAgICAgICAgICAgICAgaW50IHN5ID0gKGludChjeSArIHNpZ255ICogc3RkOjpwb3coc2lnbnkgKiB5LCBleHBvbmVudCkgKiBtKSAlIGltYWdlU2l6ZS55ICsgaW1hZ2VTaXplLnkpICUgaW1hZ2VTaXplLnk7CgogICAgICAgICAgICAgICAgaW50IHR4ID0gKChjeCArIHgpICUgaW1hZ2VTaXplLnggKyBpbWFnZVNpemUueCkgJSBpbWFnZVNpemUueDsKICAgICAgICAgICAgICAgIGludCB0eSA9ICgoY3kgKyB5KSAlIGltYWdlU2l6ZS55ICsgaW1hZ2VTaXplLnkpICUgaW1hZ2VTaXplLnk7CgogICAgICAgICAgICAgICAgaW1hZ2Uuc2V0UGl4ZWwodHgsIHR5LCBpbWFnZTIuZ2V0UGl4ZWwoc3gsIHN5KSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cn0KCmludCBtYWluKCkKewogICAgc3RkOjpzcmFuZChzdGF0aWNfY2FzdDx1bnNpZ25lZD4oc3RkOjp0aW1lKDApKSk7CgogICAgY29uc3QgaW50IHdpZHRoICA9IDUxMjsKICAgIGNvbnN0IGludCBoZWlnaHQgPSAyNTY7CgogICAgc2Y6OkltYWdlIHR4dF9iaXQ7CiAgICBzZjo6SW1hZ2UgdHh0X3dhbGw7CiAgICBzZjo6SW1hZ2UgdHh0X25vaXNlOwogICAgc2Y6OkltYWdlIHR4dF9kcm9wczsKICAgIHNmOjpJbWFnZSB0eHRfcmVzdWx0OwoKICAgIHR4dF9iaXQuY3JlYXRlKHdpZHRoLCBoZWlnaHQsIHNmOjpDb2xvcjo6QmxhY2spIDsKICAgIHR4dF93YWxsLmNyZWF0ZSh3aWR0aCwgaGVpZ2h0LCBzZjo6Q29sb3I6OkJsYWNrKSA7CiAgICB0eHRfbm9pc2UuY3JlYXRlKHdpZHRoLCBoZWlnaHQsIHNmOjpDb2xvcjo6QmxhY2spIDsKICAgIHR4dF9kcm9wcy5jcmVhdGUod2lkdGgsIGhlaWdodCwgc2Y6OkNvbG9yOjpCbGFjaykgOwogICAgdHh0X3Jlc3VsdC5jcmVhdGUod2lkdGgsIGhlaWdodCwgc2Y6OkNvbG9yOjpCbGFjaykgOwoKICAgIC8vdHh0X2JpdC5zZXRTbW9vdGgoZmFsc2UpOwogICAgLy90eHRfd2FsbC5TZXRTbW9vdGgoZmFsc2UpOwogICAgLy90eHRfbm9pc2UuU2V0U21vb3RoKGZhbHNlKTsKICAgIC8vdHh0X2Ryb3BzLlNldFNtb290aChmYWxzZSk7CiAgICAvL3R4dF9yZXN1bHQuU2V0U21vb3RoKGZhbHNlKTsKCiAgICAvKgogICAgYml0KHR4dF9iaXQsIDE2LCA2NCwgMzIpOwogICAgbWVkaWFuKHR4dF9iaXQsIDIpOwogICAgLy8qLwoKICAgIC8qCiAgICBiaXQodHh0X2JpdCwgMzIsIDY0LCAxNik7CiAgICBtZWRpYW4odHh0X2JpdCwgMik7CiAgICAvLyovCgogICAgLyoKICAgIGJpdCh0eHRfYml0LCA2NCwgMzIsIDE2KTsKICAgIG1lZGlhbih0eHRfYml0LCAyKTsKICAgIC8vKi8KCiAgICAvKgogICAgYml0KHR4dF9iaXQsIDQsIDgsIDE2KTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIC8vKi8KCiAgICAvKgogICAgYml0KHR4dF9iaXQsIDE2LCA4LCAxNik7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICBtZWRpYW4odHh0X2JpdCwgMSk7CiAgICAvLyovCgogICAgLyoKICAgIGJpdCh0eHRfYml0LCAxNSwgMTYsIDE3KTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIG1lZGlhbih0eHRfYml0LCAxKTsKICAgIC8vKi8KCiAgICAvLy8qCiAgICBiaXQodHh0X2JpdCwgMzUsIDcwLCAxNDApOwogICAgbWVkaWFuKHR4dF9iaXQsIDEpOwogICAgbWVkaWFuKHR4dF9iaXQsIDIpOwogICAgLy8qLwoKICAgIHdhbGwodHh0X3dhbGwsIHRydWUpOwogICAgbm9pc2UodHh0X25vaXNlKTsKICAgIHdoaXRlRHJvcHModHh0X2Ryb3BzLCAyNTAsIDQwLCA4MCwgZmFsc2UsIDEyNSk7CiAgICBibGVuZCh0eHRfcmVzdWx0LCB0eHRfZHJvcHMsIHR4dF9ub2lzZSwgMTUsIDUpOwogICAgbWVkaWFuKHR4dF9yZXN1bHQsIDEpOwogICAgYmxlbmQodHh0X3Jlc3VsdCwgdHh0X3dhbGwsIHR4dF9yZXN1bHQsIDEzLCAyKTsKICAgIG1hZ25pZnlpbmdEcm9wcyh0eHRfcmVzdWx0LCAxMCwgNDAsIDUwLCAxLjE1KTsKICAgIHBpeGVsaXplKHR4dF9yZXN1bHQsIDQpOwoKICAgIHNmOjpUZXh0dXJlIHJlc3VsdFRleHR1cmUgOwogICAgcmVzdWx0VGV4dHVyZS5sb2FkRnJvbUltYWdlKHR4dF9yZXN1bHQpIDsKICAgIHJlc3VsdFRleHR1cmUuc2V0U21vb3RoKHRydWUpIDsKICAgIHNmOjpTcHJpdGUgc3ByaXRlKHJlc3VsdFRleHR1cmUpOwoKCiAgICAvL3BpeGVsaXplKHR4dF9iaXQsIDIpOwogICAgLy9zZjo6U3ByaXRlIHNwcml0ZSh0eHRfYml0KTsKCiAgICBzZjo6UmVuZGVyV2luZG93IHdpbmRvdyhzZjo6VmlkZW9Nb2RlKHdpZHRoICogMiwgaGVpZ2h0ICogMiwgMzIpLCAiUHJvY2VkdXJhbCBUZXh0dXJlcyEiKTsKCiAgICB3aW5kb3cuc2V0VmVydGljYWxTeW5jRW5hYmxlZCh0cnVlKTsKCiAgICBib29sIFJ1bm5pbmcgPSB0cnVlOwoKICAgIHdoaWxlIChSdW5uaW5nKQogICAgewogICAgICAgIHNmOjpFdmVudCBFdmVudDsKCiAgICAgICAgd2hpbGUgKHdpbmRvdy5wb2xsRXZlbnQoRXZlbnQpKQogICAgICAgIHsKICAgICAgICAgICAgaWYgKEV2ZW50LnR5cGUgPT0gc2Y6OkV2ZW50OjpDbG9zZWQpCiAgICAgICAgICAgICAgICBSdW5uaW5nID0gZmFsc2U7CgogICAgICAgICAgICBpZiAoKEV2ZW50LnR5cGUgPT0gc2Y6OkV2ZW50OjpLZXlQcmVzc2VkKSAmJiAoRXZlbnQua2V5LmNvZGUgPT0gc2Y6OktleWJvYXJkOjpFc2NhcGUpKQogICAgICAgICAgICAgICAgUnVubmluZyA9IGZhbHNlOwogICAgICAgIH0KCgogICAgICAgIHdpbmRvdy5jbGVhcigpOwoKICAgICAgICB3aW5kb3cuZHJhdyhzcHJpdGUpOwogICAgICAgIHNwcml0ZS5tb3ZlKHN0YXRpY19jYXN0PGZsb2F0Pih3aWR0aCksIDAuMGYpOwogICAgICAgIHdpbmRvdy5kcmF3KHNwcml0ZSk7CiAgICAgICAgc3ByaXRlLm1vdmUoMC4wZiwgc3RhdGljX2Nhc3Q8ZmxvYXQ+KGhlaWdodCkpOwogICAgICAgIHdpbmRvdy5kcmF3KHNwcml0ZSk7CiAgICAgICAgc3ByaXRlLm1vdmUoc3RhdGljX2Nhc3Q8ZmxvYXQ+KC0gd2lkdGgpLCAwLjBmKTsKICAgICAgICB3aW5kb3cuZHJhdyhzcHJpdGUpOwogICAgICAgIHNwcml0ZS5tb3ZlKDAuMGYsIHN0YXRpY19jYXN0PGZsb2F0PigtIGhlaWdodCkpOwoKICAgICAgICB3aW5kb3cuZGlzcGxheSgpOwogICAgfQp9