#include <iostream>
#include <iomanip>
#include <vector>
//#include <vec-simple.h>
#ifndef VECSIMPLE_H
#define VECSIMPLE_H
#ifndef VEC_H
#define VEC_H
#include <ostream>
#define ASSERT(n) (n);
using namespace std;
template <size_t Dim,typename Number> class vec
{
public:
typedef Number NumberT;
static const size_t DimN=Dim;
Number items[Dim];
vec()
{
}
vec(const vec<Dim,Number >& src)
{
for(size_t i=Dim;i--;)
{
items[i]=src[i];
}
}
vec(const Number* src)
{
for(size_t i=Dim;i--;)
{
items[i]=src[i];
}
}
size_t maxPos() const
{
size_t ret=0;
for(size_t i=Dim;--i;)
{
if(items[i]>items[ret])
{
ret=i;
}
}
return(ret);
}
ostream& print(ostream& out) const
{
out<<"{ ";
for(size_t i=0;i<Dim;i++)
{
out<<setw(6)<<items[i]<<" ";
}
out<<"} ";
return(out);
}
static vec<Dim,Number > fill(const Number& val=0)
{
vec<Dim, Number> ret;
for(size_t i=Dim;i--;)
{
ret[i]=val;
}
return(ret);
}
bool operator!=(const vec<Dim,Number>&v)
{
for(size_t i=Dim;i--;)
{
if(v[i]!=items[i])
{
return(true);
}
}
return(false);
}
Number& operator [](size_t index)
{
return(items[index]);
}
const Number& operator [](size_t index) const
{
return(items[index]);
}
};
template<size_t Dim,typename Number>vec<Dim,Number > operator+(vec<Dim,Number > lhs, const vec<Dim,Number >& rhs)
{
for(size_t i=Dim;i--;)
{
lhs[i]+=rhs[i];
}
return(lhs);
}
template<size_t Dim,typename Number>vec<Dim,Number > operator-(vec<Dim,Number > lhs, const vec<Dim,Number >& rhs)
{
for(size_t i=Dim;i--;)
{
lhs[i]-=rhs[i];
}
return(lhs);
}
template<size_t Dim,typename Number>vec<Dim,Number > operator*(vec<Dim,Number > lhs, const Number& rhs)
{
for(size_t i=Dim;i--;)
{
lhs[i]*=rhs;
}
return(lhs);
}
template<size_t Dim,typename Number>vec<Dim,Number > operator/(vec<Dim,Number > lhs, const Number& rhs)
{
for(size_t i=Dim;i--;)
{
lhs[i]/=rhs;
}
return(lhs);
}
template<size_t Dim,typename Number> Number operator*(const vec<Dim,Number >&lhs, const vec<Dim,Number >& rhs)
{
Number ret=0;
for(size_t i=Dim;i--;)
{
ret+=lhs[i]*rhs[i];
}
return(ret);
}
template<size_t len,size_t Dim, typename Number> vec<len,Number > proj(const vec<Dim,Number> &v,size_t start=0)
{
return(vec<len,Number >(&v.items[start]));
}
template<size_t len,size_t Dim, typename Number> vec<len,Number > dive(const vec<Dim,Number> &v,size_t start=0)
{
vec<len,Number> ret(&v.items[start]);
for(size_t i=Dim+start;i<len;i++)
{
ret[i]=1;
}
return(ret);
}
template<size_t Dim,typename Number> ostream& operator<<(ostream& os,const vec<Dim,Number >& v)
{
return(v.print(os));
}
template<size_t DimRows,size_t DimCols,typename Number> class mat;
template<size_t DimCols,size_t DimRows,typename Number> struct dt
{
static Number det(const mat<DimRows,DimCols,Number>& src)
{
Number ret=0;
for(size_t i=DimCols;i--;)
{
ret+=src[0][i]*src.algAdd(0,i);
}
return(ret);
}
};
template<typename Number> struct dt<1,1,Number>
{
static Number det(const mat<1,1,Number>& src)
{
return(src[0][0]);
}
};
template<size_t DimRows,size_t DimCols,typename Number> class mat
{
vec<DimCols,Number> rows[DimRows];
public:
typedef Number NumberT;
static size_t shift(size_t in,const size_t& val)
{
return(in<val ? in : ++in);
}
mat()
{
}
mat(const mat<DimRows,DimCols,Number >& src)
{
for(size_t i=DimCols;i--;)
{
for(size_t j=DimRows;j--;)
{
const Number t=src[i][j];
rows[i][j]=t;
}
}
}
ostream& print(ostream& out) const
{
for(size_t i=0;i<DimRows;i++)
{
out<<rows[i]<<"\n";
}
return(out);
}
vec<DimCols,Number > minimums()
{
vec<DimCols,Number > ret=rows[0];
for(size_t i=DimRows;--i;)
{
for(size_t j=DimCols;j--;)
{
ret[j]=min(ret[j],rows[i][j]);
}
}
return(ret);
}
vec<DimCols,Number > maximums()
{
vec<DimCols,Number > ret=rows[0];
for(size_t i=DimRows;--i;)
{
for(size_t j=DimCols;j--;)
{
ret[j]=max(ret[j],rows[i][j]);
}
}
return(ret);
}
vec<DimCols,Number>& operator[] (size_t index)
{
return(rows[index]);
}
const vec<DimCols,Number>& operator[] (size_t index) const
{
return(rows[index]);
}
static mat<DimCols,DimRows,Number> ones()
{
mat<DimCols,DimRows,Number> ret;
for(size_t i=DimRows;i--;)
{
for(size_t j=DimCols;j--;)
{
ret[i][j]=(i==j);
}
}
return(ret);
}
Number det() const
{
return(dt<DimCols,DimRows,Number>::det(*this));
}
mat<DimRows-1,DimCols-1,Number> minor(size_t row,size_t col) const
{
mat<DimRows-1,DimCols-1,Number> ret;
for(size_t i=DimRows-1;i--;)
{
for(size_t j=DimCols-1;j--;)
{
ret[i][j]=rows[ret.shift(i,row)][ret.shift(j,col)];
}
}
return(ret);
}
Number algAdd(size_t row,size_t col) const
{
return(minor(row,col).det()*( (row+col)%2 ? -1 : 1));
}
mat<DimRows,DimCols,Number> Adjacent()const
{
mat<DimRows,DimCols,Number> ret;
for(size_t i=DimRows;i--;)
{
for(size_t j=DimCols;j--;)
{
ret[i][j]=algAdd(i,j);
}
}
return(ret);
}
mat<DimRows,DimCols,Number> invertT()const
{
mat<DimRows,DimCols,Number> ret=Adjacent();
return(ret/(ret[0]*rows[0]));
}
void setCol(const Number& val,size_t col)
{
for(size_t i=DimRows;i--;)
{
rows[i][col]=val;
}
}
};
template<size_t Dim,typename Number>vec<Dim,Number > operator*(const mat<Dim,Dim,Number >& lhs, const vec<Dim,Number>& rhs)
{
vec<Dim,Number> ret;
for(size_t i=Dim;i--;)
{
ret[i]=lhs[i]*rhs;
}
return(ret);
}
template<size_t DimCols,size_t DimRows,typename Number>mat<DimCols,DimRows,Number > operator/(mat<DimCols,DimRows,Number> lhs, const Number& rhs)
{
for(size_t i=DimRows;i--;)
{
lhs[i]=lhs[i]/rhs;
}
return(lhs);
}
template<size_t DimRows,size_t DimCols,typename Number> ostream& operator<<(ostream& os,const mat<DimRows,DimCols,Number>& v)
{
return(v.print(os));
}
typedef mat<2,2,float > tempMat;
#endif // VEC_H
#endif // VECSIMPLE_H
using namespace std;
typedef vec<3,float> pixel;
class screen
{
vector<pixel > buffer;
size_t width;
size_t height;
public:
screen(size_t width,size_t height):width(width),height(height)
{
buffer.assign(width*height,pixel());
}
template<typename t> void putpixel(const t& location,const pixel& px)
{
buffer[location[0]+location[1]*width]=px;
}
ostream& print(ostream& out) const
{
for(size_t i=0;i<height;i++)
{
out<<"|";
for(size_t j=0;j<width;j++)
{
const size_t mp=buffer[i+j*width].maxPos();
static const char syms[]={' ','.','\'','-','+','*'};
static const char syms2[]={'R','G','B'};
if(buffer[i+j*width][mp] > static_cast<pixel::NumberT>(sizeof(syms)-1)/static_cast<pixel::NumberT>(sizeof(syms)))
{
cout<<syms2[mp];
}
else
{
const size_t idx=buffer[i+j*width][mp]*float(sizeof(syms)-1);
out<<syms[idx];
}
}
out<<"|\n";
}
return(out);
}
};
typedef vec<3,float > v3i;
typedef vec<2,float > v2i;
typedef mat<3,3,float> m3i;
template<typename V>class allPointsOfSquare
{
vec<V::DimN,typename V::NumberT> topLeft;
vec<V::DimN,typename V::NumberT> bottomRight;
vec<V::DimN,typename V::NumberT> pos;
public:
allPointsOfSquare(const V& topLeft,const V& bottomRight):topLeft(topLeft),bottomRight(bottomRight),pos(topLeft)
{
}
const v2i& operator *() const
{
return(pos);
}
bool next()
{
const bool ret=(pos!=bottomRight);
for(size_t i=V::DimN;i--;)
{
pos[i]++;
if(pos[i]>bottomRight[i])
{
pos[i]=0;
}
else
{
break;
}
}
return(ret);
}
};
class IShader
{
public:
virtual ~IShader()
{
}
virtual pixel shade(const v3i& a)=0;
};
class baryShader:public IShader
{
public:
virtual ~baryShader()
{
}
virtual pixel shade(const v3i&a)
{
return(a);
}
};
void fillTria(mat<3,3,float > coord,IShader* shader,screen& scr)
{
//находим углы прямоугольника, в котором лежит треугольник.
//это соответственно минимумы и максимумы сторон, его содержащих
v3i topLeft=coord.minimums();
v3i bottomRight=coord.maximums();
coord.setCol(1,2);
mat<3,3,float > bcm=coord.invertT();
mat<3,2,float > directions;
for(size_t i=3;i--;)
{
directions[i]=proj<2>(coord[ (i+1) % 3 ])-proj<2>(coord[i]);
}
for(allPointsOfSquare<v2i> sweep=allPointsOfSquare<v2i>(
proj<2>(topLeft),
proj<2>(bottomRight))
;
sweep.next()
;
)
{
size_t i=0;
for(;i<3;i++)
{
v2i curDirection=(*sweep)-proj<2>(coord[i]);
tempMat crss;
crss[0]=proj<2>(curDirection);
crss[1]=proj<2>(directions[i]);
if(crss.det()>0)
{
break;
}
}
if(i==3)
{
v3i a=bcm*dive<3>(*sweep);
scr.putpixel(*sweep,shader->shade(a));
}
}
}
ostream& operator<<(ostream& os,const screen& v)
{
return(v.print(os));
}
int main()
{
screen scr(80,80);
// cout<<scr;
mat<3,3,float > t;
t[0][0]=5;
t[0][1]=7;
t[0][2]=3;
t[1][0]=70;
t[1][1]=13;
t[1][2]=13;
t[2][0]=20;
t[2][1]=50;
t[2][2]=21;
cerr<<"started";
baryShader bs;
fillTria(t,&bs,scr);
cerr<<"filled";
cout<<scr;
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgoKI2luY2x1ZGUgPGlvbWFuaXA+CiNpbmNsdWRlIDx2ZWN0b3I+CgovLyNpbmNsdWRlIDx2ZWMtc2ltcGxlLmg+CgojaWZuZGVmIFZFQ1NJTVBMRV9ICiNkZWZpbmUgVkVDU0lNUExFX0gKI2lmbmRlZiBWRUNfSAojZGVmaW5lIFZFQ19ICiNpbmNsdWRlIDxvc3RyZWFtPgoKI2RlZmluZSBBU1NFUlQobikgKG4pOwp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGUgPHNpemVfdCBEaW0sdHlwZW5hbWUgTnVtYmVyPiBjbGFzcyB2ZWMKewoKcHVibGljOgogICAgdHlwZWRlZiBOdW1iZXIgTnVtYmVyVDsKICAgIHN0YXRpYyBjb25zdCBzaXplX3QgRGltTj1EaW07CiAgICBOdW1iZXIgaXRlbXNbRGltXTsKCiAgICB2ZWMoKQogICAgewoKICAgIH0KCiAgICB2ZWMoY29uc3QgdmVjPERpbSxOdW1iZXIgPiYgc3JjKQogICAgewogICAgICAgIGZvcihzaXplX3QgaT1EaW07aS0tOykKICAgICAgICB7CiAgICAgICAgICAgIGl0ZW1zW2ldPXNyY1tpXTsKICAgICAgICB9CiAgICB9CgogICAgdmVjKGNvbnN0IE51bWJlciogc3JjKQogICAgewogICAgICAgIGZvcihzaXplX3QgaT1EaW07aS0tOykKICAgICAgICB7CiAgICAgICAgICAgIGl0ZW1zW2ldPXNyY1tpXTsKICAgICAgICB9CiAgICB9CgogICAgc2l6ZV90IG1heFBvcygpIGNvbnN0CiAgICB7CiAgICAgICAgc2l6ZV90IHJldD0wOwogICAgICAgIGZvcihzaXplX3QgaT1EaW07LS1pOykKICAgICAgICB7CiAgICAgICAgICAgIGlmKGl0ZW1zW2ldPml0ZW1zW3JldF0pCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHJldD1pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybihyZXQpOwogICAgfQoKICAgIG9zdHJlYW0mIHByaW50KG9zdHJlYW0mIG91dCkgY29uc3QKICAgIHsKICAgICAgICBvdXQ8PCJ7ICI7CiAgICAgICAgZm9yKHNpemVfdCBpPTA7aTxEaW07aSsrKQogICAgICAgIHsKICAgICAgICAgICAgb3V0PDxzZXR3KDYpPDxpdGVtc1tpXTw8IiAiOwogICAgICAgIH0KICAgICAgICBvdXQ8PCJ9ICI7CiAgICAgICAgcmV0dXJuKG91dCk7CiAgICB9CiAgICBzdGF0aWMgdmVjPERpbSxOdW1iZXIgPiBmaWxsKGNvbnN0IE51bWJlciYgdmFsPTApCiAgICB7CiAgICAgICAgdmVjPERpbSwgTnVtYmVyPiByZXQ7CiAgICAgICAgZm9yKHNpemVfdCBpPURpbTtpLS07KQogICAgICAgIHsKICAgICAgICAgICAgcmV0W2ldPXZhbDsKICAgICAgICB9CiAgICAgICAgcmV0dXJuKHJldCk7CiAgICB9CgogICAgYm9vbCBvcGVyYXRvciE9KGNvbnN0IHZlYzxEaW0sTnVtYmVyPiZ2KQogICAgewogICAgICAgIGZvcihzaXplX3QgaT1EaW07aS0tOykKICAgICAgICB7CiAgICAgICAgICAgIGlmKHZbaV0hPWl0ZW1zW2ldKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICByZXR1cm4odHJ1ZSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuKGZhbHNlKTsKICAgIH0KCiAgICBOdW1iZXImIG9wZXJhdG9yIFtdKHNpemVfdCBpbmRleCkKICAgIHsKICAgICAgICByZXR1cm4oaXRlbXNbaW5kZXhdKTsKICAgIH0KICAgIGNvbnN0IE51bWJlciYgb3BlcmF0b3IgW10oc2l6ZV90IGluZGV4KSBjb25zdAogICAgewogICAgICAgIHJldHVybihpdGVtc1tpbmRleF0pOwogICAgfQp9OwoKdGVtcGxhdGU8c2l6ZV90IERpbSx0eXBlbmFtZSBOdW1iZXI+dmVjPERpbSxOdW1iZXIgPiBvcGVyYXRvcisodmVjPERpbSxOdW1iZXIgPiBsaHMsIGNvbnN0IHZlYzxEaW0sTnVtYmVyID4mIHJocykKewogICAgZm9yKHNpemVfdCBpPURpbTtpLS07KQogICAgewogICAgICAgIGxoc1tpXSs9cmhzW2ldOwogICAgfQogICAgcmV0dXJuKGxocyk7Cgp9Cgp0ZW1wbGF0ZTxzaXplX3QgRGltLHR5cGVuYW1lIE51bWJlcj52ZWM8RGltLE51bWJlciA+IG9wZXJhdG9yLSh2ZWM8RGltLE51bWJlciA+IGxocywgY29uc3QgdmVjPERpbSxOdW1iZXIgPiYgcmhzKQp7CiAgICBmb3Ioc2l6ZV90IGk9RGltO2ktLTspCiAgICB7CiAgICAgICAgbGhzW2ldLT1yaHNbaV07CiAgICB9CiAgICByZXR1cm4obGhzKTsKfQoKdGVtcGxhdGU8c2l6ZV90IERpbSx0eXBlbmFtZSBOdW1iZXI+dmVjPERpbSxOdW1iZXIgPiBvcGVyYXRvcioodmVjPERpbSxOdW1iZXIgPiBsaHMsIGNvbnN0IE51bWJlciYgcmhzKQp7CiAgICBmb3Ioc2l6ZV90IGk9RGltO2ktLTspCiAgICB7CiAgICAgICAgbGhzW2ldKj1yaHM7CiAgICB9CiAgICByZXR1cm4obGhzKTsKfQoKCgp0ZW1wbGF0ZTxzaXplX3QgRGltLHR5cGVuYW1lIE51bWJlcj52ZWM8RGltLE51bWJlciA+IG9wZXJhdG9yLyh2ZWM8RGltLE51bWJlciA+IGxocywgY29uc3QgTnVtYmVyJiByaHMpCnsKICAgIGZvcihzaXplX3QgaT1EaW07aS0tOykKICAgIHsKICAgICAgICBsaHNbaV0vPXJoczsKICAgIH0KICAgIHJldHVybihsaHMpOwp9CgoKdGVtcGxhdGU8c2l6ZV90IERpbSx0eXBlbmFtZSBOdW1iZXI+IE51bWJlciBvcGVyYXRvciooY29uc3QgdmVjPERpbSxOdW1iZXIgPiZsaHMsIGNvbnN0IHZlYzxEaW0sTnVtYmVyID4mIHJocykKewogICAgTnVtYmVyIHJldD0wOwogICAgZm9yKHNpemVfdCBpPURpbTtpLS07KQogICAgewogICAgICAgIHJldCs9bGhzW2ldKnJoc1tpXTsKICAgIH0KICAgIHJldHVybihyZXQpOwp9CgoKdGVtcGxhdGU8c2l6ZV90IGxlbixzaXplX3QgRGltLCB0eXBlbmFtZSBOdW1iZXI+IHZlYzxsZW4sTnVtYmVyID4gcHJvaihjb25zdCB2ZWM8RGltLE51bWJlcj4gJnYsc2l6ZV90IHN0YXJ0PTApCnsKICAgIHJldHVybih2ZWM8bGVuLE51bWJlciA+KCZ2Lml0ZW1zW3N0YXJ0XSkpOwp9Cgp0ZW1wbGF0ZTxzaXplX3QgbGVuLHNpemVfdCBEaW0sIHR5cGVuYW1lIE51bWJlcj4gdmVjPGxlbixOdW1iZXIgPiBkaXZlKGNvbnN0IHZlYzxEaW0sTnVtYmVyPiAmdixzaXplX3Qgc3RhcnQ9MCkKewogICAgdmVjPGxlbixOdW1iZXI+IHJldCgmdi5pdGVtc1tzdGFydF0pOwogICAgZm9yKHNpemVfdCBpPURpbStzdGFydDtpPGxlbjtpKyspCiAgICB7CiAgICAgICAgcmV0W2ldPTE7CiAgICB9CiAgICByZXR1cm4ocmV0KTsKfQoKdGVtcGxhdGU8c2l6ZV90IERpbSx0eXBlbmFtZSBOdW1iZXI+IG9zdHJlYW0mIG9wZXJhdG9yPDwob3N0cmVhbSYgb3MsY29uc3QgdmVjPERpbSxOdW1iZXIgPiYgdikKewogICAgcmV0dXJuKHYucHJpbnQob3MpKTsKfQoKdGVtcGxhdGU8c2l6ZV90IERpbVJvd3Msc2l6ZV90IERpbUNvbHMsdHlwZW5hbWUgTnVtYmVyPiBjbGFzcyBtYXQ7Cgp0ZW1wbGF0ZTxzaXplX3QgRGltQ29scyxzaXplX3QgRGltUm93cyx0eXBlbmFtZSBOdW1iZXI+IHN0cnVjdCBkdAp7CiAgICBzdGF0aWMgTnVtYmVyIGRldChjb25zdCBtYXQ8RGltUm93cyxEaW1Db2xzLE51bWJlcj4mIHNyYykKICAgIHsKICAgICAgICBOdW1iZXIgcmV0PTA7CiAgICAgICAgZm9yKHNpemVfdCBpPURpbUNvbHM7aS0tOykKICAgICAgICB7CiAgICAgICAgICAgIHJldCs9c3JjWzBdW2ldKnNyYy5hbGdBZGQoMCxpKTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuKHJldCk7CiAgICB9Cn07Cgp0ZW1wbGF0ZTx0eXBlbmFtZSBOdW1iZXI+IHN0cnVjdCBkdDwxLDEsTnVtYmVyPgp7CiAgICBzdGF0aWMgTnVtYmVyIGRldChjb25zdCBtYXQ8MSwxLE51bWJlcj4mIHNyYykKICAgIHsKICAgICAgICByZXR1cm4oc3JjWzBdWzBdKTsKICAgIH0KfTsKCnRlbXBsYXRlPHNpemVfdCBEaW1Sb3dzLHNpemVfdCBEaW1Db2xzLHR5cGVuYW1lIE51bWJlcj4gY2xhc3MgbWF0CnsKICAgIHZlYzxEaW1Db2xzLE51bWJlcj4gcm93c1tEaW1Sb3dzXTsKCgpwdWJsaWM6CiAgICB0eXBlZGVmIE51bWJlciBOdW1iZXJUOwogICAgc3RhdGljIHNpemVfdCBzaGlmdChzaXplX3QgaW4sY29uc3Qgc2l6ZV90JiB2YWwpCiAgICB7CiAgICAgICAgcmV0dXJuKGluPHZhbCA/IGluIDogKytpbik7CiAgICB9CgogICAgbWF0KCkKICAgIHsKICAgIH0KICAgIG1hdChjb25zdCBtYXQ8RGltUm93cyxEaW1Db2xzLE51bWJlciA+JiBzcmMpCiAgICB7CiAgICAgICAgZm9yKHNpemVfdCBpPURpbUNvbHM7aS0tOykKICAgICAgICB7CiAgICAgICAgICAgIGZvcihzaXplX3Qgaj1EaW1Sb3dzO2otLTspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIGNvbnN0IE51bWJlciB0PXNyY1tpXVtqXTsKICAgICAgICAgICAgICAgIHJvd3NbaV1bal09dDsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBvc3RyZWFtJiBwcmludChvc3RyZWFtJiBvdXQpIGNvbnN0CiAgICB7CiAgICAgICAgZm9yKHNpemVfdCBpPTA7aTxEaW1Sb3dzO2krKykKICAgICAgICB7CiAgICAgICAgICAgIG91dDw8cm93c1tpXTw8IlxuIjsKICAgICAgICB9CiAgICAgICAgcmV0dXJuKG91dCk7CiAgICB9CiAgICB2ZWM8RGltQ29scyxOdW1iZXIgPiBtaW5pbXVtcygpCiAgICB7CiAgICAgICAgdmVjPERpbUNvbHMsTnVtYmVyID4gcmV0PXJvd3NbMF07CiAgICAgICAgZm9yKHNpemVfdCBpPURpbVJvd3M7LS1pOykKICAgICAgICB7CiAgICAgICAgICAgIGZvcihzaXplX3Qgaj1EaW1Db2xzO2otLTspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHJldFtqXT1taW4ocmV0W2pdLHJvd3NbaV1bal0pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybihyZXQpOwogICAgfQoKICAgIHZlYzxEaW1Db2xzLE51bWJlciA+IG1heGltdW1zKCkKICAgIHsKICAgICAgICB2ZWM8RGltQ29scyxOdW1iZXIgPiByZXQ9cm93c1swXTsKICAgICAgICBmb3Ioc2l6ZV90IGk9RGltUm93czstLWk7KQogICAgICAgIHsKICAgICAgICAgICAgZm9yKHNpemVfdCBqPURpbUNvbHM7ai0tOykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcmV0W2pdPW1heChyZXRbal0scm93c1tpXVtqXSk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuKHJldCk7CiAgICB9CiAgICB2ZWM8RGltQ29scyxOdW1iZXI+JiBvcGVyYXRvcltdIChzaXplX3QgaW5kZXgpCiAgICB7CiAgICAgICAgcmV0dXJuKHJvd3NbaW5kZXhdKTsKICAgIH0KCiAgICBjb25zdCB2ZWM8RGltQ29scyxOdW1iZXI+JiBvcGVyYXRvcltdIChzaXplX3QgaW5kZXgpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuKHJvd3NbaW5kZXhdKTsKICAgIH0KICAgIHN0YXRpYyBtYXQ8RGltQ29scyxEaW1Sb3dzLE51bWJlcj4gb25lcygpCiAgICB7CiAgICAgICAgbWF0PERpbUNvbHMsRGltUm93cyxOdW1iZXI+IHJldDsKICAgICAgICBmb3Ioc2l6ZV90IGk9RGltUm93cztpLS07KQogICAgICAgIHsKICAgICAgICAgICAgZm9yKHNpemVfdCBqPURpbUNvbHM7ai0tOykKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcmV0W2ldW2pdPShpPT1qKTsKICAgICAgICAgICAgfQoKICAgICAgICB9CiAgICAgICAgcmV0dXJuKHJldCk7CiAgICB9CgogICAgTnVtYmVyIGRldCgpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuKGR0PERpbUNvbHMsRGltUm93cyxOdW1iZXI+OjpkZXQoKnRoaXMpKTsKICAgIH0KCiAgICBtYXQ8RGltUm93cy0xLERpbUNvbHMtMSxOdW1iZXI+IG1pbm9yKHNpemVfdCByb3csc2l6ZV90IGNvbCkgY29uc3QKICAgIHsKICAgICAgICBtYXQ8RGltUm93cy0xLERpbUNvbHMtMSxOdW1iZXI+IHJldDsKICAgICAgICBmb3Ioc2l6ZV90IGk9RGltUm93cy0xO2ktLTspCiAgICAgICAgewogICAgICAgICAgICBmb3Ioc2l6ZV90IGo9RGltQ29scy0xO2otLTspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHJldFtpXVtqXT1yb3dzW3JldC5zaGlmdChpLHJvdyldW3JldC5zaGlmdChqLGNvbCldOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHJldHVybihyZXQpOwogICAgfQoKCiAgICBOdW1iZXIgYWxnQWRkKHNpemVfdCByb3csc2l6ZV90IGNvbCkgY29uc3QKICAgIHsKICAgICAgICByZXR1cm4obWlub3Iocm93LGNvbCkuZGV0KCkqKCAocm93K2NvbCklMiA/IC0xIDogMSkpOwogICAgfQoKICAgIG1hdDxEaW1Sb3dzLERpbUNvbHMsTnVtYmVyPiBBZGphY2VudCgpY29uc3QKICAgIHsKICAgICAgICBtYXQ8RGltUm93cyxEaW1Db2xzLE51bWJlcj4gcmV0OwogICAgICAgIGZvcihzaXplX3QgaT1EaW1Sb3dzO2ktLTspCiAgICAgICAgewogICAgICAgICAgICBmb3Ioc2l6ZV90IGo9RGltQ29scztqLS07KQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICByZXRbaV1bal09YWxnQWRkKGksaik7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuKHJldCk7CiAgICB9CgogICAgbWF0PERpbVJvd3MsRGltQ29scyxOdW1iZXI+IGludmVydFQoKWNvbnN0CiAgICB7CiAgICAgICAgbWF0PERpbVJvd3MsRGltQ29scyxOdW1iZXI+IHJldD1BZGphY2VudCgpOwogICAgICAgIHJldHVybihyZXQvKHJldFswXSpyb3dzWzBdKSk7CiAgICB9CgogICAgdm9pZCBzZXRDb2woY29uc3QgTnVtYmVyJiB2YWwsc2l6ZV90IGNvbCkKICAgIHsKICAgICAgICBmb3Ioc2l6ZV90IGk9RGltUm93cztpLS07KQogICAgICAgIHsKICAgICAgICAgICAgcm93c1tpXVtjb2xdPXZhbDsKICAgICAgICB9CiAgICB9Cgp9OwoKdGVtcGxhdGU8c2l6ZV90IERpbSx0eXBlbmFtZSBOdW1iZXI+dmVjPERpbSxOdW1iZXIgPiBvcGVyYXRvciooY29uc3QgbWF0PERpbSxEaW0sTnVtYmVyID4mIGxocywgY29uc3QgdmVjPERpbSxOdW1iZXI+JiByaHMpCnsKICAgIHZlYzxEaW0sTnVtYmVyPiByZXQ7CiAgICBmb3Ioc2l6ZV90IGk9RGltO2ktLTspCiAgICB7CiAgICAgICAgcmV0W2ldPWxoc1tpXSpyaHM7CiAgICB9CiAgICByZXR1cm4ocmV0KTsKfQoKdGVtcGxhdGU8c2l6ZV90IERpbUNvbHMsc2l6ZV90IERpbVJvd3MsdHlwZW5hbWUgTnVtYmVyPm1hdDxEaW1Db2xzLERpbVJvd3MsTnVtYmVyID4gb3BlcmF0b3IvKG1hdDxEaW1Db2xzLERpbVJvd3MsTnVtYmVyPiBsaHMsIGNvbnN0IE51bWJlciYgcmhzKQp7CiAgICBmb3Ioc2l6ZV90IGk9RGltUm93cztpLS07KQogICAgewogICAgICAgIGxoc1tpXT1saHNbaV0vcmhzOwogICAgfQogICAgcmV0dXJuKGxocyk7Cn0KCnRlbXBsYXRlPHNpemVfdCBEaW1Sb3dzLHNpemVfdCBEaW1Db2xzLHR5cGVuYW1lIE51bWJlcj4gb3N0cmVhbSYgb3BlcmF0b3I8PChvc3RyZWFtJiBvcyxjb25zdCBtYXQ8RGltUm93cyxEaW1Db2xzLE51bWJlcj4mIHYpCnsKICAgIHJldHVybih2LnByaW50KG9zKSk7Cn0KCnR5cGVkZWYgbWF0PDIsMixmbG9hdCA+IHRlbXBNYXQ7CgojZW5kaWYgLy8gVkVDX0gKCgojZW5kaWYgLy8gVkVDU0lNUExFX0gKCgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCnR5cGVkZWYgdmVjPDMsZmxvYXQ+IHBpeGVsOwoKY2xhc3Mgc2NyZWVuCnsKICAgIHZlY3RvcjxwaXhlbCA+IGJ1ZmZlcjsKICAgIHNpemVfdCB3aWR0aDsKICAgIHNpemVfdCBoZWlnaHQ7CnB1YmxpYzoKICAgIHNjcmVlbihzaXplX3Qgd2lkdGgsc2l6ZV90IGhlaWdodCk6d2lkdGgod2lkdGgpLGhlaWdodChoZWlnaHQpCiAgICB7CiAgICAgICAgYnVmZmVyLmFzc2lnbih3aWR0aCpoZWlnaHQscGl4ZWwoKSk7CiAgICB9CiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSB0PiB2b2lkIHB1dHBpeGVsKGNvbnN0IHQmIGxvY2F0aW9uLGNvbnN0IHBpeGVsJiBweCkKICAgIHsKCiAgICAgICAgYnVmZmVyW2xvY2F0aW9uWzBdK2xvY2F0aW9uWzFdKndpZHRoXT1weDsKICAgIH0KCiAgICBvc3RyZWFtJiBwcmludChvc3RyZWFtJiBvdXQpIGNvbnN0CiAgICB7CiAgICAgICAgZm9yKHNpemVfdCBpPTA7aTxoZWlnaHQ7aSsrKQogICAgICAgIHsKICAgICAgICAgICAgb3V0PDwifCI7CiAgICAgICAgICAgIGZvcihzaXplX3Qgaj0wO2o8d2lkdGg7aisrKQogICAgICAgICAgICB7ICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgY29uc3Qgc2l6ZV90IG1wPWJ1ZmZlcltpK2oqd2lkdGhdLm1heFBvcygpOwogICAgICAgICAgICAgICAgc3RhdGljIGNvbnN0IGNoYXIgc3ltc1tdPXsnICcsJy4nLCdcJycsJy0nLCcrJywnKid9OwogICAgICAgICAgICAgICAgc3RhdGljIGNvbnN0IGNoYXIgc3ltczJbXT17J1InLCdHJywnQid9OwogICAgICAgICAgICAgICAgaWYoYnVmZmVyW2kraip3aWR0aF1bbXBdID4gc3RhdGljX2Nhc3Q8cGl4ZWw6Ok51bWJlclQ+KHNpemVvZihzeW1zKS0xKS9zdGF0aWNfY2FzdDxwaXhlbDo6TnVtYmVyVD4oc2l6ZW9mKHN5bXMpKSkKICAgICAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgICAgICBjb3V0PDxzeW1zMlttcF07CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgICAgICBlbHNlCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2l6ZV90IGlkeD1idWZmZXJbaStqKndpZHRoXVttcF0qZmxvYXQoc2l6ZW9mKHN5bXMpLTEpOwogICAgICAgICAgICAgICAgICAgIG91dDw8c3ltc1tpZHhdOwogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIG91dDw8InxcbiI7CiAgICAgICAgfQogICAgICAgIHJldHVybihvdXQpOwogICAgfQp9OwoKdHlwZWRlZiB2ZWM8MyxmbG9hdCA+IHYzaTsKdHlwZWRlZiB2ZWM8MixmbG9hdCA+IHYyaTsKdHlwZWRlZiBtYXQ8MywzLGZsb2F0PiAgbTNpOwoKCnRlbXBsYXRlPHR5cGVuYW1lIFY+Y2xhc3MgYWxsUG9pbnRzT2ZTcXVhcmUKewogICAgdmVjPFY6OkRpbU4sdHlwZW5hbWUgVjo6TnVtYmVyVD4gdG9wTGVmdDsKICAgIHZlYzxWOjpEaW1OLHR5cGVuYW1lIFY6Ok51bWJlclQ+IGJvdHRvbVJpZ2h0OwogICAgdmVjPFY6OkRpbU4sdHlwZW5hbWUgVjo6TnVtYmVyVD4gcG9zOwpwdWJsaWM6CiAgICBhbGxQb2ludHNPZlNxdWFyZShjb25zdCBWJiB0b3BMZWZ0LGNvbnN0IFYmIGJvdHRvbVJpZ2h0KTp0b3BMZWZ0KHRvcExlZnQpLGJvdHRvbVJpZ2h0KGJvdHRvbVJpZ2h0KSxwb3ModG9wTGVmdCkKICAgIHsKICAgIH0KICAgIGNvbnN0IHYyaSYgb3BlcmF0b3IgKigpIGNvbnN0CiAgICB7CiAgICAgICAgcmV0dXJuKHBvcyk7CiAgICB9CiAgICBib29sIG5leHQoKQogICAgewogICAgICAgIGNvbnN0IGJvb2wgcmV0PShwb3MhPWJvdHRvbVJpZ2h0KTsKICAgICAgICBmb3Ioc2l6ZV90IGk9Vjo6RGltTjtpLS07KQogICAgICAgIHsKICAgICAgICAgICAgcG9zW2ldKys7CiAgICAgICAgICAgIGlmKHBvc1tpXT5ib3R0b21SaWdodFtpXSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcG9zW2ldPTA7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgZWxzZQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4ocmV0KTsKICAgIH0KfTsKCmNsYXNzIElTaGFkZXIKewpwdWJsaWM6CiAgICB2aXJ0dWFsIH5JU2hhZGVyKCkKICAgIHsKCiAgICB9CgogICAgdmlydHVhbCBwaXhlbCBzaGFkZShjb25zdCB2M2kmIGEpPTA7Cn07CgpjbGFzcyBiYXJ5U2hhZGVyOnB1YmxpYyBJU2hhZGVyCnsKcHVibGljOgogICAgdmlydHVhbCB+YmFyeVNoYWRlcigpCiAgICB7CgogICAgfQoKICAgIHZpcnR1YWwgcGl4ZWwgc2hhZGUoY29uc3QgdjNpJmEpCiAgICB7CiAgICAgICAgcmV0dXJuKGEpOwogICAgfQp9OwoKCnZvaWQgZmlsbFRyaWEobWF0PDMsMyxmbG9hdCA+IGNvb3JkLElTaGFkZXIqIHNoYWRlcixzY3JlZW4mIHNjcikKewogICAgLy/QvdCw0YXQvtC00LjQvCDRg9Cz0LvRiyDQv9GA0Y/QvNC+0YPQs9C+0LvRjNC90LjQutCwLCDQsiDQutC+0YLQvtGA0L7QvCDQu9C10LbQuNGCINGC0YDQtdGD0LPQvtC70YzQvdC40LouCiAgICAvL9GN0YLQviDRgdC+0L7RgtCy0LXRgtGB0YLQstC10L3QvdC+INC80LjQvdC40LzRg9C80Ysg0Lgg0LzQsNC60YHQuNC80YPQvNGLINGB0YLQvtGA0L7QvSwg0LXQs9C+INGB0L7QtNC10YDQttCw0YnQuNGFCgogICAgdjNpIHRvcExlZnQ9Y29vcmQubWluaW11bXMoKTsKICAgIHYzaSBib3R0b21SaWdodD1jb29yZC5tYXhpbXVtcygpOwoKICAgIGNvb3JkLnNldENvbCgxLDIpOwoKICAgIG1hdDwzLDMsZmxvYXQgPiBiY209Y29vcmQuaW52ZXJ0VCgpOwoKICAgIG1hdDwzLDIsZmxvYXQgPiBkaXJlY3Rpb25zOwoKICAgIGZvcihzaXplX3QgaT0zO2ktLTspCiAgICB7CiAgICAgICAgZGlyZWN0aW9uc1tpXT1wcm9qPDI+KGNvb3JkWyAoaSsxKSAlIDMgXSktcHJvajwyPihjb29yZFtpXSk7CiAgICB9CgogICAgZm9yKGFsbFBvaW50c09mU3F1YXJlPHYyaT4gc3dlZXA9YWxsUG9pbnRzT2ZTcXVhcmU8djJpPigKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2o8Mj4odG9wTGVmdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9qPDI+KGJvdHRvbVJpZ2h0KSkKICAgICAgICAgICAgICAgICAgICAgICAgOwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dlZXAubmV4dCgpCiAgICAgICAgICAgICAgICAgICAgICAgIDsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgewogICAgICAgICAgICBzaXplX3QgaT0wOwogICAgICAgICAgICBmb3IoO2k8MztpKyspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHYyaSBjdXJEaXJlY3Rpb249KCpzd2VlcCktcHJvajwyPihjb29yZFtpXSk7CgogICAgICAgICAgICAgICAgdGVtcE1hdCBjcnNzOwogICAgICAgICAgICAgICAgY3Jzc1swXT1wcm9qPDI+KGN1ckRpcmVjdGlvbik7CiAgICAgICAgICAgICAgICBjcnNzWzFdPXByb2o8Mj4oZGlyZWN0aW9uc1tpXSk7CgogICAgICAgICAgICAgICAgaWYoY3Jzcy5kZXQoKT4wKQogICAgICAgICAgICAgICAgeyAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYoaT09MykKICAgICAgICAgICAgeyAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIHYzaSBhPWJjbSpkaXZlPDM+KCpzd2VlcCk7CgogICAgICAgICAgICAgICAgc2NyLnB1dHBpeGVsKCpzd2VlcCxzaGFkZXItPnNoYWRlKGEpKTsKCiAgICAgICAgICAgIH0KICAgIH0KfQoKCgoKb3N0cmVhbSYgb3BlcmF0b3I8PChvc3RyZWFtJiBvcyxjb25zdCBzY3JlZW4mIHYpCnsKICAgIHJldHVybih2LnByaW50KG9zKSk7Cn0KCgoKCmludCBtYWluKCkKewogICAgc2NyZWVuIHNjcig4MCw4MCk7Ci8vICAgIGNvdXQ8PHNjcjsKICAgIG1hdDwzLDMsZmxvYXQgPiB0OwogICAgdFswXVswXT01OwogICAgdFswXVsxXT03OwogICAgdFswXVsyXT0zOwoKCiAgICB0WzFdWzBdPTcwOwogICAgdFsxXVsxXT0xMzsKICAgIHRbMV1bMl09MTM7CgoKCiAgICB0WzJdWzBdPTIwOwogICAgdFsyXVsxXT01MDsKICAgIHRbMl1bMl09MjE7CiAgICBjZXJyPDwic3RhcnRlZCI7CgoKICAgIGJhcnlTaGFkZXIgYnM7CiAgICBmaWxsVHJpYSh0LCZicyxzY3IpOwogICAgY2Vycjw8ImZpbGxlZCI7CgogICAgY291dDw8c2NyOwoKICAgIHJldHVybiAwOwp9Cgo=