#ifndef FURROVINERMATRIX4_H
#define FURROVINERMATRIX4_H
#include <Furrovine++/Core.h>
#include <Furrovine++/Quaternion.h>
namespace Furrovine {
template <typename T> struct RMatrix4 {
public:
union {
struct {
#ifdef FURROVINEMATRIX_ROWMAJOR
T m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44;
#else
T m11, m21, m31, m41,
m12, m22, m32, m42,
m13, m23, m33, m43,
m14, m24, m34, m44;
#endif /* FURROVINEMATRIX_ROWMAJOR */
};
T m[16];
struct {
typename MatrixTraits<T>::TApi4 api;
};
RVector4<T> rows[4];
};
RMatrix4<T>& Set ( T x11 = T(1), T x21 = T(0), T x31 = T(0), T x41 = T(0),
T x12 = T(0), T x22 = T(1), T x32 = T(0), T x42 = T(0),
T x13 = T(0), T x23 = T(0), T x33 = T(1), T x43 = T(0),
T x14 = T(0), T x24 = T(0), T x34 = T(0), T x44 = T(1) ) {
m11 = x11;
m12 = x12;
m13 = x13;
m14 = x14;
m21 = x21;
m22 = x22;
m23 = x23;
m24 = x24;
m31 = x31;
m32 = x32;
m33 = x33;
m34 = x34;
m41 = x41;
m42 = x42;
m43 = x43;
m44 = x44;
return *this;
}
RMatrix4<T>& Set ( bool memorder,
T x01, T x02, T x03, T x04,
T x05, T x06, T x07, T x08,
T x09, T x10, T x11, T x12,
T x13, T x14, T x15, T x16 ) {
m[0] = x01;
m[1] = x02;
m[2] = x03;
m[3] = x04;
m[4] = x05;
m[5] = x06;
m[6] = x07;
m[7] = x08;
m[8] = x09;
m[9] = x10;
m[10] = x11;
m[11] = x12;
m[12] = x13;
m[13] = x14;
m[14] = x15;
m[15] = x16;
return *this;
}
void Identify () {
m12 = m13 = m14 = m21 = m23 = m24 = m31 = m32 = m34 = m41 = m42 = m43 = 0;
m11 = m22 = m33 = m44 = (T)1;
}
RMatrix4<T> Clone () {
RMatrix4<T> r;
memcpy(m, r.m, sizeof(T) * 16);
return r;
}
RMatrix4<T>& Clone (const RMatrix4<T>& obj) {
memcpy(m, obj.m, sizeof(T) * 16);
return *this;
}
RMatrix4<T>& Transpose () {
Mem::Swap<T>(m12, m21);
Mem::Swap<T>(m13, m31);
Mem::Swap<T>(m14, m41);
Mem::Swap<T>(m32, m23);
Mem::Swap<T>(m34, m43);
Mem::Swap<T>(m42, m24);
return *this;
}
TVector3<T> Transform (const TVector3<T>& source) {
return *this * source;
}
TVector4<T> Transform (const TVector4<T>& source) {
return *this * source;
}
void Transform (const TVector3<T>& source, TVector3<T>& out) {
T w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1];
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1];
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1];
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1];
out /= w;
}
void Transform (const TVector4<T>& source, TVector4<T>& out) {
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1] * source.w;
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1] * source.w;
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1] * source.w;
out.w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1] * source.w;
}
void Transform (const TVector4<T>& source, TVector3<T>& out) {
T w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1] * source.w;
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1] * source.w;
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1] * source.w;
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1] * source.w;
out /= w;
}
TVector3<T> Transform (const TVector3<T>& source) const {
return *this * source;
}
TVector4<T> Transform (const TVector4<T>& source) const {
return *this * source;
}
void Transform (const TVector3<T>& source, TVector3<T>& out) const {
T w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1];
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1];
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1];
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1];
out /= w;
}
void Transform (const TVector4<T>& source, TVector4<T>& out) const {
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1] * source.w;
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1] * source.w;
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1] * source.w;
out.w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1] * source.w;
}
void Transform (const TVector4<T>& source, TVector3<T>& out) const {
T w = m[4 * 1 - 1] * source.x +
m[4 * 2 - 1] * source.y +
m[4 * 3 - 1] * source.z +
m[4 * 4 - 1] * source.w;
out.x = m[1 * 1 - 1] * source.x +
m[1 * 2 - 1] * source.y +
m[1 * 3 - 1] * source.z +
m[1 * 4 - 1] * source.w;
out.y = m[2 * 1 - 1] * source.x +
m[2 * 2 - 1] * source.y +
m[2 * 3 - 1] * source.z +
m[2 * 4 - 1] * source.w;
out.z = m[3 * 1 - 1] * source.x +
m[3 * 2 - 1] * source.y +
m[3 * 3 - 1] * source.z +
m[3 * 4 - 1] * source.w;
out /= w;
}
T Determinant () {
T a0 = m[0] * m[5] - m[1] * m[4];
T a1 = m[0] * m[6] - m[2] * m[4];
T a2 = m[0] * m[7] - m[3] * m[4];
T a3 = m[1] * m[6] - m[2] * m[5];
T a4 = m[1] * m[7] - m[3] * m[5];
T a5 = m[2] * m[7] - m[3] * m[6];
T b0 = m[8] * m[13] - m[9] * m[12];
T b1 = m[8] * m[14] - m[10] * m[12];
T b2 = m[8] * m[15] - m[11] * m[12];
T b3 = m[9] * m[14] - m[10] * m[13];
T b4 = m[9] * m[15] - m[11] * m[13];
T b5 = m[10] * m[15] - m[11] * m[14];
T det = a0*b5 - a1*b4 + a2*b3 + a3*b2 - a4*b1 + a5*b0;
return det;
}
RMatrix4<T> Inverse () {
T a0 = m[0] * m[5] - m[1] * m[4];
T a1 = m[0] * m[6] - m[2] * m[4];
T a2 = m[0] * m[7] - m[3] * m[4];
T a3 = m[1] * m[6] - m[2] * m[5];
T a4 = m[1] * m[7] - m[3] * m[5];
T a5 = m[2] * m[7] - m[3] * m[6];
T b0 = m[8] * m[13] - m[9] * m[12];
T b1 = m[8] * m[14] - m[10] * m[12];
T b2 = m[8] * m[15] - m[11] * m[12];
T b3 = m[9] * m[14] - m[10] * m[13];
T b4 = m[9] * m[15] - m[11] * m[13];
T b5 = m[10] * m[15] - m[11] * m[14];
T det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
RMatrix4<T> inverse;
if (Mathema<T>::Abs(det) > T(0)) {
inverse.m[0] = + m[5] * b5 - m[6] * b4 + m[7] * b3;
inverse.m[4] = - m[4] * b5 + m[6] * b2 - m[7] * b1;
inverse.m[8] = + m[4] * b4 - m[5] * b2 + m[7] * b0;
inverse.m[12] = - m[4] * b3 + m[5] * b1 - m[6] * b0;
inverse.m[1] = - m[1] * b5 + m[2] * b4 - m[3] * b3;
inverse.m[5] = + m[0] * b5 - m[2] * b2 + m[3] * b1;
inverse.m[9] = - m[0] * b4 + m[1] * b2 - m[3] * b0;
inverse.m[13] = + m[0] * b3 - m[1] * b1 + m[2] * b0;
inverse.m[2] = + m[13] * a5 - m[14] * a4 + m[15] * a3;
inverse.m[6] = - m[12] * a5 + m[14] * a2 - m[15] * a1;
inverse.m[10] = + m[12] * a4 - m[13] * a2 + m[15] * a0;
inverse.m[14] = - m[12] * a3 + m[13] * a1 - m[14] * a0;
inverse.m[3] = - m[9] * a5 + m[10] * a4 - m[11] * a3;
inverse.m[7] = + m[8] * a5 - m[10] * a2 + m[11] * a1;
inverse.m[11] = - m[8] * a4 + m[9] * a2 - m[11] * a0;
inverse.m[15] = + m[8] * a3 - m[9] * a1 + m[10] * a0;
T invDet = (T(1)) / det;
inverse.m[0] *= invDet;
inverse.m[1] *= invDet;
inverse.m[2] *= invDet;
inverse.m[3] *= invDet;
inverse.m[4] *= invDet;
inverse.m[5] *= invDet;
inverse.m[6] *= invDet;
inverse.m[7] *= invDet;
inverse.m[8] *= invDet;
inverse.m[9] *= invDet;
inverse.m[10] *= invDet;
inverse.m[11] *= invDet;
inverse.m[12] *= invDet;
inverse.m[13] *= invDet;
inverse.m[14] *= invDet;
inverse.m[15] *= invDet;
return inverse;
}
inverse.Identify();
return inverse;
}
bool Invert () {
T a0 = m[0] * m[5] - m[1] * m[4];
T a1 = m[0] * m[6] - m[2] * m[4];
T a2 = m[0] * m[7] - m[3] * m[4];
T a3 = m[1] * m[6] - m[2] * m[5];
T a4 = m[1] * m[7] - m[3] * m[5];
T a5 = m[2] * m[7] - m[3] * m[6];
T b0 = m[8] * m[13] - m[9] * m[12];
T b1 = m[8] * m[14] - m[10] * m[12];
T b2 = m[8] * m[15] - m[11] * m[12];
T b3 = m[9] * m[14] - m[10] * m[13];
T b4 = m[9] * m[15] - m[11] * m[13];
T b5 = m[10] * m[15] - m[11] * m[14];
T det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
if (Mathema<T>::Abs(det) > T(0)) {
RMatrix4<T> inverse;
inverse.m[0] = + m[5] * b5 - m[6] * b4 + m[7] * b3;
inverse.m[4] = - m[4] * b5 + m[6] * b2 - m[7] * b1;
inverse.m[8] = + m[4] * b4 - m[5] * b2 + m[7] * b0;
inverse.m[12] = - m[4] * b3 + m[5] * b1 - m[6] * b0;
inverse.m[1] = - m[1] * b5 + m[2] * b4 - m[3] * b3;
inverse.m[5] = + m[0] * b5 - m[2] * b2 + m[3] * b1;
inverse.m[9] = - m[0] * b4 + m[1] * b2 - m[3] * b0;
inverse.m[13] = + m[0] * b3 - m[1] * b1 + m[2] * b0;
inverse.m[2] = + m[13] * a5 - m[14] * a4 + m[15] * a3;
inverse.m[6] = - m[12] * a5 + m[14] * a2 - m[15] * a1;
inverse.m[10] = + m[12] * a4 - m[13] * a2 + m[15] * a0;
inverse.m[14] = - m[12] * a3 + m[13] * a1 - m[14] * a0;
inverse.m[3] = - m[9] * a5 + m[10] * a4 - m[11] * a3;
inverse.m[7] = + m[8] * a5 - m[10] * a2 + m[11] * a1;
inverse.m[11] = - m[8] * a4 + m[9] * a2 - m[11] * a0;
inverse.m[15] = + m[8] * a3 - m[9] * a1 + m[10] * a0;
T invDet = (T(1)) / det;
inverse.m[0] *= invDet;
inverse.m[1] *= invDet;
inverse.m[2] *= invDet;
inverse.m[3] *= invDet;
inverse.m[4] *= invDet;
inverse.m[5] *= invDet;
inverse.m[6] *= invDet;
inverse.m[7] *= invDet;
inverse.m[8] *= invDet;
inverse.m[9] *= invDet;
inverse.m[10] *= invDet;
inverse.m[11] *= invDet;
inverse.m[12] *= invDet;
inverse.m[13] *= invDet;
inverse.m[14] *= invDet;
inverse.m[15] *= invDet;
Clone(inverse);
return true;
}
return false;
}
void Decompose (TVector3<T>& outscale, TQuaternion<T>& outrotate, TVector3<T>& outtranslation) {
T mdiag = Mathema<T>::Sqrt(m[0] + m[5] + m[10] + m[15]);
T mdiag2 = 2 * mdiag;
#ifdef FURROVINEMATRIX_ROWMAJOR
outscale.x = Mathema<T>::Sqrt(m11 * m11 + m21 * m21 * m31 * m31);
outscale.y = Mathema<T>::Sqrt(m12 * m12 + m22 * m22 * m32 * m32);
outscale.z = Mathema<T>::Sqrt(m13 * m13 + m23 * m23 * m33 * m33);
outtranslation.x = m14;
outtranslation.y = m24;
outtranslation.z = m34;
outrotate.x = (m[6] - m[9]) / mdiag2;
outrotate.y = (m[8] - m[2]) / mdiag2;
outrotate.z = (m[1] - m[4]) / mdiag2;
outrotate.w = mdiag / 2;
#else
outtranslation.x = m[3];
outtranslation.y = m[7];
outtranslation.z = m[11];
outscale.x = Mathema<T>::Sqrt(m[0] * m[0] + m[1] * m[1] + m[2] * m[2]);
outscale.y = Mathema<T>::Sqrt(m[4] * m[4] + m[5] * m[5] + m[6] * m[6]);
outscale.z = Mathema<T>::Sqrt(m[8] * m[8] + m[9] * m[9] + m[10] * m[10]);
outrotate.x = (m[6] - m[9]) / mdiag2;
outrotate.y = (m[8] - m[2]) / mdiag2;
outrotate.z = (m[1] - m[4]) / mdiag2;
outrotate.w = mdiag / 2;
#endif
}
void Decompose (TVector3<T>& outscale, TVector3<T>& outrotate, TVector3<T>& ouTranslate) {
#ifdef FURROVINEMATRIX_ROWMAJOR
outscale.x = Mathema<T>::Sqrt(m11 * m11 + m21 * m21 * m31 * m31);
outscale.y = Mathema<T>::Sqrt(m12 * m12 + m22 * m22 * m32 * m32);
outscale.z = Mathema<T>::Sqrt(m13 * m13 + m23 * m23 * m33 * m33);
ouTranslate.x = m14;
ouTranslate.y = m24;
ouTranslate.z = m34;
outrotate.x = (m[6] - m[9]) / mdiag2;
outrotate.y = (m[8] - m[2]) / mdiag2;
outrotate.z = (m[1] - m[4]) / mdiag2;
outrotate.w = mdiag / 2;
#else
ouTranslate.x = m[3];
ouTranslate.y = m[7];
ouTranslate.z = m[11];
outscale.x = Mathema<T>::Sqrt(m[0] * m[0] + m[1] * m[1] + m[2] * m[2]);
outscale.y = Mathema<T>::Sqrt(m[4] * m[4] + m[5] * m[5] + m[6] * m[6]);
outscale.z = Mathema<T>::Sqrt(m[8] * m[8] + m[9] * m[9] + m[10] * m[10]);
outrotate.y = Mathema<T>::Asin(-m[8]);
T theta = Mathema<T>::Cos(outrotate.y);
outrotate.x = Mathema<T>::Asin(Mathema<T>::Mod(m[9] / theta, T(1)) );
outrotate.z = Mathema<T>::Asin(Mathema<T>::Mod(m[4] / theta, T(1)) );
#endif
}
RMatrix4<T> operator+ (const RMatrix4<T>& right) const {
RMatrix4<T> r = {
m[0] + right.m[0],
m[1] + right.m[1],
m[2] + right.m[2],
m[3] + right.m[3],
m[4] + right.m[4],
m[5] + right.m[5],
m[6] + right.m[6],
m[7] + right.m[7],
m[8] + right.m[8],
m[9] + right.m[9],
m[10] + right.m[10],
m[11] + right.m[11],
m[12] + right.m[12],
m[13] + right.m[13],
m[14] + right.m[14],
m[15] + right.m[15]
};
return r;
}
RMatrix4<T> operator- (const RMatrix4<T>& right) const {
RMatrix4<T> r = {
m[0] - right.m[0],
m[1] - right.m[1],
m[2] - right.m[2],
m[3] - right.m[3],
m[4] - right.m[4],
m[5] - right.m[5],
m[6] - right.m[6],
m[7] - right.m[7],
m[8] - right.m[8],
m[9] - right.m[9],
m[10] - right.m[10],
m[11] - right.m[11],
m[12] - right.m[12],
m[13] - right.m[13],
m[14] - right.m[14],
m[15] - right.m[15]
};
return r;
}
RMatrix4<T> operator* (const T& right) const {
RMatrix4<T> r = {
m[0] * right,
m[1] * right,
m[2] * right,
m[3] * right,
m[4] * right,
m[5] * right,
m[6] * right,
m[7] * right,
m[8] * right,
m[9] * right,
m[10] * right,
m[11] * right,
m[12] * right,
m[13] * right,
m[14] * right,
m[15] * right
};
return r;
}
RMatrix4<T> operator/ (const T& right) const {
if (right == T(0)) {
RMatrix4<T> z = { 0 };
return z;
}
T invright = (T(1)) / right;
RMatrix4<T> r = {
m[0] * invright,
m[1] * invright,
m[2] * invright,
m[3] * invright,
m[4] * invright,
m[5] * invright,
m[6] * invright,
m[7] * invright,
m[8] * invright,
m[9] * invright,
m[10] * invright,
m[11] * invright,
m[12] * invright,
m[13] * invright,
m[14] * invright,
m[15] * invright };
return r;
}
RMatrix4<T>& operator+= (const RMatrix4<T>& right) {
m[0] += right.m[0];
m[1] += right.m[1];
m[2] += right.m[2];
m[3] += right.m[3];
m[4] += right.m[4];
m[5] += right.m[5];
m[6] += right.m[6];
m[7] += right.m[7];
m[8] += right.m[8];
m[9] += right.m[9];
m[10] += right.m[10];
m[11] += right.m[11];
m[12] += right.m[12];
m[13] += right.m[13];
m[14] += right.m[14];
m[15] += right.m[15];
return *this;
}
RMatrix4<T>& operator-= (const RMatrix4<T>& right) {
m[0] -= right.m[0];
m[1] -= right.m[1];
m[2] -= right.m[2];
m[3] -= right.m[3];
m[4] -= right.m[4];
m[5] -= right.m[5];
m[6] -= right.m[6];
m[7] -= right.m[7];
m[8] -= right.m[8];
m[9] -= right.m[9];
m[10] -= right.m[10];
m[11] -= right.m[11];
m[12] -= right.m[12];
m[13] -= right.m[13];
m[14] -= right.m[14];
m[15] -= right.m[15];
return *this;
}
RMatrix4<T>& operator*= (const T& right) {
m[0] *= right;
m[1] *= right;
m[2] *= right;
m[3] *= right;
m[4] *= right;
m[5] *= right;
m[6] *= right;
m[7] *= right;
m[8] *= right;
m[9] *= right;
m[10] *= right;
m[11] *= right;
m[12] *= right;
m[13] *= right;
m[14] *= right;
m[15] *= right;
return *this;
}
RMatrix4<T>& operator/= (const T& right) {
if (right == T(0))
return *this;
T invright = (T(1)) / right;
m[0] *= invright;
m[1] *= invright;
m[2] *= invright;
m[3] *= invright;
m[4] *= invright;
m[5] *= invright;
m[6] *= invright;
m[7] *= invright;
m[8] *= invright;
m[9] *= invright;
m[10] *= invright;
m[11] *= invright;
m[12] *= invright;
m[13] *= invright;
m[14] *= invright;
m[15] *= invright;
return *this;
}
TVector4<T> operator* ( const TVector4<T>& right ) {
return TVector4<T>(
m[1 * 1 - 1] * right.x +
m[1 * 2 - 1] * right.y +
m[1 * 3 - 1] * right.z +
m[1 * 4 - 1] * right.w,
m[2 * 1 - 1] * right.x +
m[2 * 2 - 1] * right.y +
m[2 * 3 - 1] * right.z +
m[2 * 4 - 1] * right.w,
m[3 * 1 - 1] * right.x +
m[3 * 2 - 1] * right.y +
m[3 * 3 - 1] * right.z +
m[3 * 4 - 1] * right.w,
m[4 * 1 - 1] * right.x +
m[4 * 2 - 1] * right.y +
m[4 * 3 - 1] * right.z +
m[4 * 4 - 1] * right.w
);
}
TVector3<T> operator* ( const TVector3<T>& right ) {
return TVector3<T> (
m[1 * 1 - 1] * right.x +
m[1 * 2 - 1] * right.y +
m[1 * 3 - 1] * right.z +
m[1 * 4 - 1],
m[2 * 1 - 1] * right.x +
m[2 * 2 - 1] * right.y +
m[2 * 3 - 1] * right.z +
m[2 * 4 - 1],
m[3 * 1 - 1] * right.x +
m[3 * 2 - 1] * right.y +
m[3 * 3 - 1] * right.z +
m[3 * 4 - 1],
m[4 * 1 - 1] * right.x +
m[4 * 2 - 1] * right.y +
m[4 * 3 - 1] * right.z +
m[4 * 4 - 1]
);
}
RMatrix4<T> operator* ( const RMatrix4<T>& right ) {
RMatrix4<T> r = {
(right.m[1 * 1 - 1] * m[1 * 1 - 1] + right.m[1 * 2 - 1] * m[2 * 1 - 1] + right.m[1 * 3 - 1] * m[3 * 1 - 1] + right.m[1 * 4 - 1] * m[4 * 1 - 1]),
(right.m[1 * 1 - 1] * m[1 * 2 - 1] + right.m[1 * 2 - 1] * m[2 * 2 - 1] + right.m[1 * 3 - 1] * m[3 * 2 - 1] + right.m[1 * 4 - 1] * m[4 * 2 - 1]),
(right.m[1 * 1 - 1] * m[1 * 3 - 1] + right.m[1 * 2 - 1] * m[2 * 3 - 1] + right.m[1 * 3 - 1] * m[3 * 3 - 1] + right.m[1 * 4 - 1] * m[4 * 3 - 1]),
(right.m[1 * 1 - 1] * m[1 * 4 - 1] + right.m[1 * 2 - 1] * m[2 * 4 - 1] + right.m[1 * 3 - 1] * m[3 * 4 - 1] + right.m[1 * 4 - 1] * m[4 * 4 - 1]),
(right.m[2 * 1 - 1] * m[1 * 1 - 1] + right.m[2 * 2 - 1] * m[2 * 1 - 1] + right.m[2 * 3 - 1] * m[3 * 1 - 1] + right.m[2 * 4 - 1] * m[4 * 1 - 1]),
(right.m[2 * 1 - 1] * m[1 * 2 - 1] + right.m[2 * 2 - 1] * m[2 * 2 - 1] + right.m[2 * 3 - 1] * m[3 * 2 - 1] + right.m[2 * 4 - 1] * m[4 * 2 - 1]),
(right.m[2 * 1 - 1] * m[1 * 3 - 1] + right.m[2 * 2 - 1] * m[2 * 3 - 1] + right.m[2 * 3 - 1] * m[3 * 3 - 1] + right.m[2 * 4 - 1] * m[4 * 3 - 1]),
(right.m[2 * 1 - 1] * m[1 * 4 - 1] + right.m[2 * 2 - 1] * m[2 * 4 - 1] + right.m[2 * 3 - 1] * m[3 * 4 - 1] + right.m[2 * 4 - 1] * m[4 * 4 - 1]),
(right.m[3 * 1 - 1] * m[1 * 1 - 1] + right.m[3 * 2 - 1] * m[2 * 1 - 1] + right.m[3 * 3 - 1] * m[3 * 1 - 1] + right.m[3 * 4 - 1] * m[4 * 1 - 1]),
(right.m[3 * 1 - 1] * m[1 * 2 - 1] + right.m[3 * 2 - 1] * m[2 * 2 - 1] + right.m[3 * 3 - 1] * m[3 * 2 - 1] + right.m[3 * 4 - 1] * m[4 * 2 - 1]),
(right.m[3 * 1 - 1] * m[1 * 3 - 1] + right.m[3 * 2 - 1] * m[2 * 3 - 1] + right.m[3 * 3 - 1] * m[3 * 3 - 1] + right.m[3 * 4 - 1] * m[4 * 3 - 1]),
(right.m[3 * 1 - 1] * m[1 * 4 - 1] + right.m[3 * 2 - 1] * m[2 * 4 - 1] + right.m[3 * 3 - 1] * m[3 * 4 - 1] + right.m[3 * 4 - 1] * m[4 * 4 - 1]),
(right.m[4 * 1 - 1] * m[1 * 1 - 1] + right.m[4 * 2 - 1] * m[2 * 1 - 1] + right.m[4 * 3 - 1] * m[3 * 1 - 1] + right.m[4 * 4 - 1] * m[4 * 1 - 1]),
(right.m[4 * 1 - 1] * m[1 * 2 - 1] + right.m[4 * 2 - 1] * m[2 * 2 - 1] + right.m[4 * 3 - 1] * m[3 * 2 - 1] + right.m[4 * 4 - 1] * m[4 * 2 - 1]),
(right.m[4 * 1 - 1] * m[1 * 3 - 1] + right.m[4 * 2 - 1] * m[2 * 3 - 1] + right.m[4 * 3 - 1] * m[3 * 3 - 1] + right.m[4 * 4 - 1] * m[4 * 3 - 1]),
(right.m[4 * 1 - 1] * m[1 * 4 - 1] + right.m[4 * 2 - 1] * m[2 * 4 - 1] + right.m[4 * 3 - 1] * m[3 * 4 - 1] + right.m[4 * 4 - 1] * m[4 * 4 - 1])
};
return r;
}
RMatrix4<T>& operator*= ( const RMatrix4<T>& right ) {
T out[16] = {
right.m[1 * 1 - 1] * m[1 * 1 - 1] + right.m[1 * 2 - 1] * m[2 * 1 - 1] + right.m[1 * 3 - 1] * m[3 * 1 - 1] + right.m[1 * 4 - 1] * m[4 * 1 - 1],
right.m[1 * 1 - 1] * m[1 * 2 - 1] + right.m[1 * 2 - 1] * m[2 * 2 - 1] + right.m[1 * 3 - 1] * m[3 * 2 - 1] + right.m[1 * 4 - 1] * m[4 * 2 - 1],
right.m[1 * 1 - 1] * m[1 * 3 - 1] + right.m[1 * 2 - 1] * m[2 * 3 - 1] + right.m[1 * 3 - 1] * m[3 * 3 - 1] + right.m[1 * 4 - 1] * m[4 * 3 - 1],
right.m[1 * 1 - 1] * m[1 * 4 - 1] + right.m[1 * 2 - 1] * m[2 * 4 - 1] + right.m[1 * 3 - 1] * m[3 * 4 - 1] + right.m[1 * 4 - 1] * m[4 * 4 - 1],
right.m[2 * 1 - 1] * m[1 * 1 - 1] + right.m[2 * 2 - 1] * m[2 * 1 - 1] + right.m[2 * 3 - 1] * m[3 * 1 - 1] + right.m[2 * 4 - 1] * m[4 * 1 - 1],
right.m[2 * 1 - 1] * m[1 * 2 - 1] + right.m[2 * 2 - 1] * m[2 * 2 - 1] + right.m[2 * 3 - 1] * m[3 * 2 - 1] + right.m[2 * 4 - 1] * m[4 * 2 - 1],
right.m[2 * 1 - 1] * m[1 * 3 - 1] + right.m[2 * 2 - 1] * m[2 * 3 - 1] + right.m[2 * 3 - 1] * m[3 * 3 - 1] + right.m[2 * 4 - 1] * m[4 * 3 - 1],
right.m[2 * 1 - 1] * m[1 * 4 - 1] + right.m[2 * 2 - 1] * m[2 * 4 - 1] + right.m[2 * 3 - 1] * m[3 * 4 - 1] + right.m[2 * 4 - 1] * m[4 * 4 - 1],
right.m[3 * 1 - 1] * m[1 * 1 - 1] + right.m[3 * 2 - 1] * m[2 * 1 - 1] + right.m[3 * 3 - 1] * m[3 * 1 - 1] + right.m[3 * 4 - 1] * m[4 * 1 - 1],
right.m[3 * 1 - 1] * m[1 * 2 - 1] + right.m[3 * 2 - 1] * m[2 * 2 - 1] + right.m[3 * 3 - 1] * m[3 * 2 - 1] + right.m[3 * 4 - 1] * m[4 * 2 - 1],
right.m[3 * 1 - 1] * m[1 * 3 - 1] + right.m[3 * 2 - 1] * m[2 * 3 - 1] + right.m[3 * 3 - 1] * m[3 * 3 - 1] + right.m[3 * 4 - 1] * m[4 * 3 - 1],
right.m[3 * 1 - 1] * m[1 * 4 - 1] + right.m[3 * 2 - 1] * m[2 * 4 - 1] + right.m[3 * 3 - 1] * m[3 * 4 - 1] + right.m[3 * 4 - 1] * m[4 * 4 - 1],
right.m[4 * 1 - 1] * m[1 * 1 - 1] + right.m[4 * 2 - 1] * m[2 * 1 - 1] + right.m[4 * 3 - 1] * m[3 * 1 - 1] + right.m[4 * 4 - 1] * m[4 * 1 - 1],
right.m[4 * 1 - 1] * m[1 * 2 - 1] + right.m[4 * 2 - 1] * m[2 * 2 - 1] + right.m[4 * 3 - 1] * m[3 * 2 - 1] + right.m[4 * 4 - 1] * m[4 * 2 - 1],
right.m[4 * 1 - 1] * m[1 * 3 - 1] + right.m[4 * 2 - 1] * m[2 * 3 - 1] + right.m[4 * 3 - 1] * m[3 * 3 - 1] + right.m[4 * 4 - 1] * m[4 * 3 - 1],
right.m[4 * 1 - 1] * m[1 * 4 - 1] + right.m[4 * 2 - 1] * m[2 * 4 - 1] + right.m[4 * 3 - 1] * m[3 * 4 - 1] + right.m[4 * 4 - 1] * m[4 * 4 - 1]
};
memcpy(m, out, sizeof(T) * 16);
return *this;
}
bool operator== ( const RMatrix4<T>& right ) {
return m[0] == right.m[0] &&
m[1] == right.m[1] &&
m[2] == right.m[2] &&
m[3] == right.m[3] &&
m[4] == right.m[4] &&
m[5] == right.m[5] &&
m[6] == right.m[6] &&
m[7] == right.m[7] &&
m[8] == right.m[8] &&
m[9] == right.m[9] &&
m[10] == right.m[10] &&
m[11] == right.m[11] &&
m[12] == right.m[12] &&
m[13] == right.m[13] &&
m[14] == right.m[14] &&
m[15] == right.m[15];
}
bool operator!= ( const RMatrix4<T>& right ) {
return !(*this == right);
}
bool operator== ( T* right ) {
return m[0] == right[0] &&
m[1] == right[1] &&
m[2] == right[2] &&
m[3] == right[3] &&
m[4] == right[4] &&
m[5] == right[5] &&
m[6] == right[6] &&
m[7] == right[7] &&
m[8] == right[8] &&
m[9] == right[9] &&
m[10] == right[10] &&
m[11] == right[11] &&
m[12] == right[12] &&
m[13] == right[13] &&
m[14] == right[14] &&
m[15] == right[15];
}
bool operator!= ( T* right ) {
return !(*this == right);
}
bool Equals (const RMatrix4<T>& right) {
return m[0] == right.m[0] &&
m[1] == right.m[1] &&
m[2] == right.m[2] &&
m[3] == right.m[3] &&
m[4] == right.m[4] &&
m[5] == right.m[5] &&
m[6] == right.m[6] &&
m[7] == right.m[7] &&
m[8] == right.m[8] &&
m[9] == right.m[9] &&
m[10] == right.m[10] &&
m[11] == right.m[11] &&
m[12] == right.m[12] &&
m[13] == right.m[13] &&
m[14] == right.m[14] &&
m[15] == right.m[15];
}
TVector4<T> operator* ( const TVector4<T>& right ) const {
return TVector4<T> (
m11 * right.x +
m12 * right.y +
m13 * right.z +
m14 * right.w,
m21 * right.x +
m22 * right.y +
m23 * right.z +
m24 * right.w,
m31 * right.x +
m32 * right.y +
m33 * right.z +
m34 * right.w,
m41 * right.x +
m42 * right.y +
m43 * right.z +
m44 * right.w
);
}
TVector3<T> operator* ( const TVector3<T>& right ) const {
return TVector3<T> (
m11 * right.x +
m12 * right.y +
m13 * right.z +
m14,
m21 * right.x +
m22 * right.y +
m23 * right.z +
m24,
m31 * right.x +
m32 * right.y +
m33 * right.z +
m34,
m41 * right.x +
m42 * right.y +
m43 * right.z +
m44
);
}
RMatrix4<T> operator* ( const RMatrix4<T>& right ) const {
RMatrix4<T> r = { m[0] * right.m[0] +
m[1] * right.m[4] +
m[2] * right.m[8] +
m[3] * right.m[12],
m[0] * right.m[1] +
m[1] * right.m[5] +
m[2] * right.m[9] +
m[3] * right.m[13],
m[0] * right.m[2] +
m[1] * right.m[6] +
m[2] * right.m[10] +
m[3] * right.m[14],
m[0] * right.m[3] +
m[1] * right.m[7] +
m[2] * right.m[11] +
m[3] * right.m[15],
m[4] * right.m[0] +
m[5] * right.m[4] +
m[6] * right.m[8] +
m[7] * right.m[12],
m[4] * right.m[1] +
m[5] * right.m[5] +
m[6] * right.m[9] +
m[7] * right.m[13],
m[4] * right.m[2] +
m[5] * right.m[6] +
m[6] * right.m[10] +
m[7] * right.m[14],
m[4] * right.m[3] +
m[5] * right.m[7] +
m[6] * right.m[11] +
m[7] * right.m[15],
m[8] * right.m[0] +
m[9] * right.m[4] +
m[10] * right.m[8] +
m[11] * right.m[12],
m[8] * right.m[1] +
m[9] * right.m[5] +
m[10] * right.m[9] +
m[11] * right.m[13],
m[8] * right.m[2] +
m[9] * right.m[6] +
m[10] * right.m[10] +
m[11] * right.m[14],
m[8] * right.m[3] +
m[9] * right.m[7] +
m[10] * right.m[11] +
m[11] * right.m[15],
m[12] * right.m[0] +
m[13] * right.m[4] +
m[14] * right.m[8] +
m[15] * right.m[12],
m[12] * right.m[1] +
m[13] * right.m[5] +
m[14] * right.m[9] +
m[15] * right.m[13],
m[12] * right.m[2] +
m[13] * right.m[6] +
m[14] * right.m[10] +
m[15] * right.m[14],
m[12] * right.m[3] +
m[13] * right.m[7] +
m[14] * right.m[11] +
m[15] * right.m[15]
};
return r;
}
bool operator== ( const RMatrix4<T>& right ) const {
return memcmp(m, right.m, sizeof(T) * 16) == 0;
}
bool operator!= ( const RMatrix4<T>& right ) const {
return memcmp(m, right.m, sizeof(T) * 16) != 0;
}
bool operator== ( T* right ) const {
return memcmp(m, right, sizeof(T) * 16) == 0;
}
bool operator!= ( T* right ) const {
return memcmp(m, right, sizeof(T) * 16) != 0;
}
operator T* () const {
return (T*)m;
}
T& operator[] (int index) {
return m[index];
}
T& operator() (int column, int row) {
return m[row * 4 + column];
}
static TVector3<T> Transform (const RMatrix4<T>& matrix, const TVector3<T>& source) {
return matrix * source;
}
static TVector4<T> Transform (const RMatrix4<T>& matrix, const TVector4<T>& source) {
return matrix * source;
}
static RMatrix4<T> Transpose (const RMatrix4<T>& matrix) {
RMatrix4<T> r = {
matrix.m[0],
matrix.m[4],
matrix.m[8],
matrix.m[12],
matrix.m[1],
matrix.m[5],
matrix.m[9],
matrix.m[13],
matrix.m[2],
matrix.m[6],
matrix.m[10],
matrix.m[14],
matrix.m[3],
matrix.m[7],
matrix.m[11],
matrix.m[15]
};
return r;
}
static RMatrix4<T> Adjoint (const RMatrix4<T>& matrix) {
T a0 = matrix.m[0] * matrix.m[5] - matrix.m[1] * matrix.m[4];
T a1 = matrix.m[0] * matrix.m[6] - matrix.m[2] * matrix.m[4];
T a2 = matrix.m[0] * matrix.m[7] - matrix.m[3] * matrix.m[4];
T a3 = matrix.m[1] * matrix.m[6] - matrix.m[2] * matrix.m[5];
T a4 = matrix.m[1] * matrix.m[7] - matrix.m[3] * matrix.m[5];
T a5 = matrix.m[2] * matrix.m[7] - matrix.m[3] * matrix.m[6];
T b0 = matrix.m[8] * matrix.m[13] - matrix.m[9] * matrix.m[12];
T b1 = matrix.m[8] * matrix.m[14] - matrix.m[10] * matrix.m[12];
T b2 = matrix.m[8] * matrix.m[15] - matrix.m[11] * matrix.m[12];
T b3 = matrix.m[9] * matrix.m[14] - matrix.m[10] * matrix.m[13];
T b4 = matrix.m[9] * matrix.m[15] - matrix.m[11] * matrix.m[13];
T b5 = matrix.m[10] * matrix.m[15] - matrix.m[11] * matrix.m[14];
RMatrix4<T> r = {
+ matrix.m[5] * b5 - matrix.m[6] * b4 + matrix.m[7] * b3,
- matrix.m[1] * b5 + matrix.m[2] * b4 - matrix.m[3] * b3,
+ matrix.m[13] * a5 - matrix.m[14] * a4 + matrix.m[15] * a3,
- matrix.m[9] * a5 + matrix.m[10] * a4 - matrix.m[11] * a3,
- matrix.m[4] * b5 + matrix.m[6] * b2 - matrix.m[7] * b1,
+ matrix.m[0] * b5 - matrix.m[2] * b2 + matrix.m[3] * b1,
- matrix.m[12] * a5 + matrix.m[14] * a2 - matrix.m[15] * a1,
+ matrix.m[8] * a5 - matrix.m[10] * a2 + matrix.m[11] * a1,
+ matrix.m[4] * b4 - matrix.m[5] * b2 + matrix.m[7] * b0,
- matrix.m[0] * b4 + matrix.m[1] * b2 - matrix.m[3] * b0,
+ matrix.m[12] * a4 - matrix.m[13] * a2 + matrix.m[15] * a0,
- matrix.m[8] * a4 + matrix.m[9] * a2 - matrix.m[11] * a0,
- matrix.m[4] * b3 + matrix.m[5] * b1 - matrix.m[6] * b0,
+ matrix.m[0] * b3 - matrix.m[1] * b1 + matrix.m[2] * b0,
- matrix.m[12] * a3 + matrix.m[13] * a1 - matrix.m[14] * a0,
+ matrix.m[8] * a3 - matrix.m[9] * a1 + matrix.m[10] * a0
};
return r;
}
static RMatrix4<T> Inverse (const RMatrix4<T>& matrix) {
T a0 = matrix.m[0] * matrix.m[5] - matrix.m[1] * matrix.m[4];
T a1 = matrix.m[0] * matrix.m[6] - matrix.m[2] * matrix.m[4];
T a2 = matrix.m[0] * matrix.m[7] - matrix.m[3] * matrix.m[4];
T a3 = matrix.m[1] * matrix.m[6] - matrix.m[2] * matrix.m[5];
T a4 = matrix.m[1] * matrix.m[7] - matrix.m[3] * matrix.m[5];
T a5 = matrix.m[2] * matrix.m[7] - matrix.m[3] * matrix.m[6];
T b0 = matrix.m[8] * matrix.m[13] - matrix.m[9] * matrix.m[12];
T b1 = matrix.m[8] * matrix.m[14] - matrix.m[10] * matrix.m[12];
T b2 = matrix.m[8] * matrix.m[15] - matrix.m[11] * matrix.m[12];
T b3 = matrix.m[9] * matrix.m[14] - matrix.m[10] * matrix.m[13];
T b4 = matrix.m[9] * matrix.m[15] - matrix.m[11] * matrix.m[13];
T b5 = matrix.m[10] * matrix.m[15] - matrix.m[11] * matrix.m[14];
T det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
RMatrix4<T> inverse = { 0 };
if (Mathema<T>::Abs(det) > T(0)) {
inverse.m[0] = + matrix.m[5] * b5 - matrix.m[6] * b4 + matrix.m[7] * b3;
inverse.m[4] = - matrix.m[4] * b5 + matrix.m[6] * b2 - matrix.m[7] * b1;
inverse.m[8] = + matrix.m[4] * b4 - matrix.m[5] * b2 + matrix.m[7] * b0;
inverse.m[12] = - matrix.m[4] * b3 + matrix.m[5] * b1 - matrix.m[6] * b0;
inverse.m[1] = - matrix.m[1] * b5 + matrix.m[2] * b4 - matrix.m[3] * b3;
inverse.m[5] = + matrix.m[0] * b5 - matrix.m[2] * b2 + matrix.m[3] * b1;
inverse.m[9] = - matrix.m[0] * b4 + matrix.m[1] * b2 - matrix.m[3] * b0;
inverse.m[13] = + matrix.m[0] * b3 - matrix.m[1] * b1 + matrix.m[2] * b0;
inverse.m[2] = + matrix.m[13] * a5 - matrix.m[14] * a4 + matrix.m[15] * a3;
inverse.m[6] = - matrix.m[12] * a5 + matrix.m[14] * a2 - matrix.m[15] * a1;
inverse.m[10] = + matrix.m[12] * a4 - matrix.m[13] * a2 + matrix.m[15] * a0;
inverse.m[14] = - matrix.m[12] * a3 + matrix.m[13] * a1 - matrix.m[14] * a0;
inverse.m[3] = - matrix.m[9] * a5 + matrix.m[10] * a4 - matrix.m[11] * a3;
inverse.m[7] = + matrix.m[8] * a5 - matrix.m[10] * a2 + matrix.m[11] * a1;
inverse.m[11] = - matrix.m[8] * a4 + matrix.m[9] * a2 - matrix.m[11] * a0;
inverse.m[15] = + matrix.m[8] * a3 - matrix.m[9] * a1 + matrix.m[10] * a0;
T invDet = (T(1)) / det;
inverse.m[0] *= invDet;
inverse.m[1] *= invDet;
inverse.m[2] *= invDet;
inverse.m[3] *= invDet;
inverse.m[4] *= invDet;
inverse.m[5] *= invDet;
inverse.m[6] *= invDet;
inverse.m[7] *= invDet;
inverse.m[8] *= invDet;
inverse.m[9] *= invDet;
inverse.m[10] *= invDet;
inverse.m[11] *= invDet;
inverse.m[12] *= invDet;
inverse.m[13] *= invDet;
inverse.m[14] *= invDet;
inverse.m[15] *= invDet;
}
return inverse;
}
static bool Invert (const RMatrix4<T>& matrix, RMatrix4<T>& out) {
T a0 = matrix.m[0] * matrix.m[5] - matrix.m[1] * matrix.m[4];
T a1 = matrix.m[0] * matrix.m[6] - matrix.m[2] * matrix.m[4];
T a2 = matrix.m[0] * matrix.m[7] - matrix.m[3] * matrix.m[4];
T a3 = matrix.m[1] * matrix.m[6] - matrix.m[2] * matrix.m[5];
T a4 = matrix.m[1] * matrix.m[7] - matrix.m[3] * matrix.m[5];
T a5 = matrix.m[2] * matrix.m[7] - matrix.m[3] * matrix.m[6];
T b0 = matrix.m[8] * matrix.m[13] - matrix.m[9] * matrix.m[12];
T b1 = matrix.m[8] * matrix.m[14] - matrix.m[10] * matrix.m[12];
T b2 = matrix.m[8] * matrix.m[15] - matrix.m[11] * matrix.m[12];
T b3 = matrix.m[9] * matrix.m[14] - matrix.m[10] * matrix.m[13];
T b4 = matrix.m[9] * matrix.m[15] - matrix.m[11] * matrix.m[13];
T b5 = matrix.m[10] * matrix.m[15] - matrix.m[11] * matrix.m[14];
T det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
if (Mathema<T>::Abs(det) > T(0)) {
out.m[0] = + matrix.m[5] * b5 - matrix.m[6] * b4 + matrix.m[7] * b3;
out.m[4] = - matrix.m[4] * b5 + matrix.m[6] * b2 - matrix.m[7] * b1;
out.m[8] = + matrix.m[4] * b4 - matrix.m[5] * b2 + matrix.m[7] * b0;
out.m[12] = - matrix.m[4] * b3 + matrix.m[5] * b1 - matrix.m[6] * b0;
out.m[1] = - matrix.m[1] * b5 + matrix.m[2] * b4 - matrix.m[3] * b3;
out.m[5] = + matrix.m[0] * b5 - matrix.m[2] * b2 + matrix.m[3] * b1;
out.m[9] = - matrix.m[0] * b4 + matrix.m[1] * b2 - matrix.m[3] * b0;
out.m[13] = + matrix.m[0] * b3 - matrix.m[1] * b1 + matrix.m[2] * b0;
out.m[2] = + matrix.m[13] * a5 - matrix.m[14] * a4 + matrix.m[15] * a3;
out.m[6] = - matrix.m[12] * a5 + matrix.m[14] * a2 - matrix.m[15] * a1;
out.m[10] = + matrix.m[12] * a4 - matrix.m[13] * a2 + matrix.m[15] * a0;
out.m[14] = - matrix.m[12] * a3 + matrix.m[13] * a1 - matrix.m[14] * a0;
out.m[3] = - matrix.m[9] * a5 + matrix.m[10] * a4 - matrix.m[11] * a3;
out.m[7] = + matrix.m[8] * a5 - matrix.m[10] * a2 + matrix.m[11] * a1;
out.m[11] = - matrix.m[8] * a4 + matrix.m[9] * a2 - matrix.m[11] * a0;
out.m[15] = + matrix.m[8] * a3 - matrix.m[9] * a1 + matrix.m[10] * a0;
T invDet = (T(1)) / det;
out.m[0] *= invDet;
out.m[1] *= invDet;
out.m[2] *= invDet;
out.m[3] *= invDet;
out.m[4] *= invDet;
out.m[5] *= invDet;
out.m[6] *= invDet;
out.m[7] *= invDet;
out.m[8] *= invDet;
out.m[9] *= invDet;
out.m[10] *= invDet;
out.m[11] *= invDet;
out.m[12] *= invDet;
out.m[13] *= invDet;
out.m[14] *= invDet;
out.m[15] *= invDet;
return true;
}
return false;
}
static RMatrix4<T> CreateTranslation (T dx, T dy, T dz) {
RMatrix4<T> r = { T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
dx, dy, dz, T(1)};
return r;
}
static RMatrix4<T> CreateTranslation (const TVector3<T>& translation) {
return CreateTranslation(translation.x, translation.y, translation.z);
}
static RMatrix4<T> CreateRotationX (T radians) {
T cosa = Mathema<T>::Cos(radians);
T sina = Mathema<T>::Sin(radians);
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
T(0), cosa, -sina, T(0),
T(0), sina, cosa, T(0),
T(0), T(0), T(0), T(1)};
return r;
}
static RMatrix4<T> CreateRotationY (T radians) {
T cosa = Mathema<T>::Cos(radians);
T sina = Mathema<T>::Sin(radians);
RMatrix4<T> r = {
cosa, T(0), sina, T(0),
T(0), T(1), T(0), T(0),
-sina, T(0), cosa, T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateRotationZ (T radians) {
T cosa = Mathema<T>::Cos(radians);
T sina = Mathema<T>::Sin(radians);
RMatrix4<T> r = {
cosa, -sina, T(0), T(0),
sina, cosa, T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateRotation (T xradians, T yradians, T zradians) {
T xcos = Mathema<T>::Cos(xradians);
T xsin = Mathema<T>::Sin(xradians);
T zcos = Mathema<T>::Cos(zradians);
T zsin = Mathema<T>::Sin(zradians);
T ycos = Mathema<T>::Cos(yradians);
T ysin = Mathema<T>::Sin(yradians);
RMatrix4<T> r = {
ycos * zcos, -xcos * zsin + xsin * ysin * zcos, xsin * zsin + xcos * ysin * zcos, T(0),
ycos * zsin, xcos * zcos + xsin * ysin * zsin, -xsin * zcos + xcos * ysin * zsin, T(0),
ysin, xsin * ycos, xcos * ycos, T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateRotation (const TVector3<T>& yawpitchroll) {
return CreateRotation(yawpitchroll.x, yawpitchroll.y, yawpitchroll.z);
}
static RMatrix4<T> CreateRotationAxis (TVector3<T> axis, T radians) {
axis.Normalize();
T cosa = Mathema<T>::Cos(radians);
T sina = Mathema<T>::Sin(radians);
T affcosa = T(1) - cosa;
RMatrix4<T> r = {
(axis.x * axis.x) * affcosa + cosa, (axis.x * axis.y) * affcosa - (axis.z * sina), (axis.x * axis.z) * affcosa + (axis.y * sina), T(0),
(axis.y * axis.x) * affcosa + (axis.z * sina), (axis.y * axis.y) * affcosa + cosa, (axis.y * axis.z) * affcosa - (axis.x * sina), T(0),
(axis.z * axis.x) * affcosa - (axis.y * sina), (axis.z * axis.y) * affcosa + (axis.x * sina), (axis.z * axis.z) * affcosa + cosa, T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateRotationQuaternion (const TQuaternion<T>& quaternion) {
T w2 = castto(T, quaternion.w * quaternion.w);
T x2 = castto(T, quaternion.x * quaternion.x);
T y2 = castto(T, quaternion.y * quaternion.y);
T z2 = castto(T, quaternion.z * quaternion.z);
T dx = castto(T, 2 * quaternion.x);
T dy = castto(T, 2 * quaternion.y);
T dw = castto(T, 2 * quaternion.w);
RMatrix4<T> r = {
w2 + x2 - y2 - z2, dx * quaternion.y - dw * quaternion.z, dx * quaternion.z + dw * quaternion.y, T(0),
dx * quaternion.y + dw * quaternion.z, w2 - x2 + y2 - z2, dy * quaternion.z + dw * quaternion.x, T(0),
dx * quaternion.z - dw * quaternion.y, dy * quaternion.z - dw * quaternion.x, w2 - x2 - y2 + z2, T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateScale (T sx, T sy, T sz) {
RMatrix4<T> r = {
sx, T(0), T(0), T(0),
T(0), sy, T(0), T(0),
T(0), T(0), sz, T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateScale (T s) {
return CreateScale(s, s, s);
}
static RMatrix4<T> CreateScale (const TVector3<T>& s) {
return CreateScale(s.x, s.y, s.z);
}
static RMatrix4<T> CreateScale (T sx, T sy, T sz, const TVector3<T>& origin) {
RMatrix4<T> r = {
sx, T(0), T(0), origin.x * (T(1) - sx),
T(0), sy, T(0), origin.y * (T(1) - sy),
T(0), T(0), sz, origin.z * (T(1) - sz),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateScale (T s, const TVector3<T>& origin) {
return CreateScale(s, s, s, origin);
}
static RMatrix4<T> CreateScale (const TVector3<T>& s, const TVector3<T>& origin) {
return CreateScale(s.x, s.y, s.z, origin);
}
static RMatrix4<T> CreateReflectionX () {
RMatrix4<T> r = {
-T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateReflectionY () {
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
T(0), -T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateReflectionZ () {
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), -T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateReflection (const TVector3<T>& normal, const TVector3<T>& origin) {
T doubledotnormorigin = ((T)2) * (normal.Dot(origin));
RMatrix4<T> r = {
T(1) - ((T)2) * normal[0] * normal[0],
-((T)2) * normal[0] * normal[1],
-((T)2) * normal[0] * normal[2],
doubledotnormorigin * normal[0],
-((T)2) * normal[1] * normal[0],
T(1) - ((T)2) * normal[1] * normal[1],
-((T)2) * normal[1] * normal[2],
doubledotnormorigin * normal[1],
-((T)2) * normal[2] * normal[0],
-((T)2) * normal[2] * normal[1],
T(1) - ((T)2) * normal[2] * normal[2],
doubledotnormorigin * normal[2],
T(0),
T(0),
T(0),
T(1)
};
return r;
}
static RMatrix4<T> CreateObliqueProjection (const TVector3<T>& normal, const TVector3<T>& origin, const TVector3<T>& direction) {
T normaldotdir = normal.Dot(direction);
T normaldotorigin = normal.Dot(origin);
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
direction[0] * normal[0] - normaldotdir,
direction[0] * normal[1],
direction[0] * normal[2],
-normaldotorigin * direction[0],
direction[1] * normal[0],
direction[1] * normal[1] - normaldotdir,
direction[1] * normal[2],
-normaldotorigin * direction[1],
-direction[2] * normal[0],
-direction[2] * normal[1],
-direction[2] * normal[2] - normaldotdir,
normaldotorigin * direction[2],
T(0),
T(0),
T(0),
-normaldotdir
};
#else
RMatrix4<T> r = {
direction[0] * normal[0] - normaldotdir,
direction[0] * normal[1],
direction[0] * normal[2],
-normaldotorigin * direction[0],
direction[1] * normal[0],
direction[1] * normal[1] - normaldotdir,
direction[1] * normal[2],
-normaldotorigin * direction[1],
direction[2] * normal[0],
direction[2] * normal[1],
direction[2] * normal[2] - normaldotdir,
-normaldotorigin * direction[2],
T(0),
T(0),
T(0),
-normaldotdir
};
#endif
return r;
}
static RMatrix4<T> CreateOrthographicProjectionOffCenter ( T left, T right, T bottom, T top ) {
return CreateOrthographicProjectionOffCenter(left, right, bottom, top, (T)-1, (T)1 );
}
static RMatrix4<T> CreateOrthographicProjectionOffCenter ( T left, T right, T bottom, T top, T nearplane, T farplane ) {
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
T(2) / (right - left), T(0), T(0), T(0),
T(0), T(2) / (top - bottom), T(0), T(0),
-T(0), -T(0), T(2) / (farplane - nearplane), -T(0),
- (right + left) / (right - left), - (top + bottom) / (top - bottom), - (farplane + nearplane) / (farplane - nearplane), T(1)
};
#else
RMatrix4<T> r = {
T(2) / (right - left), T(0), T(0), T(0),
T(0), T(2) / (top - bottom), T(0), T(0),
T(0), T(0), -T(2) / (farplane - nearplane), T(0),
- (right + left) / (right - left), - (top + bottom) / (top - bottom), - (farplane + nearplane) / (farplane - nearplane), T(1)
};
#endif
return r;
}
static RMatrix4<T> CreateOrthographicProjection ( T left, T right, T bottom, T top ) {
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
T(2) / (right - left), T(0), T(0), T(0),
T(0), T(2) / (top - bottom), T(0), T(0),
-T(0), -T(0), T(1), -T(0),
- (right + left) / (right - left), - (top + bottom) / (top - bottom), T(0), T(1)
};
#else
RMatrix4<T> r = {
T(2) / (right - left), T(0), T(0), T(0),
T(0), T(2) / (top - bottom), T(0), T(0),
T(0), T(0), -T(1), T(0),
- (right + left) / (right - left), - (top + bottom) / (top - bottom), T(0), T(1)
};
#endif
return r;
}
static RMatrix4<T> CreatePerspectiveProjection ( T left, T right, T bottom, T top, T nearplane, T farplane ) {
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> = r {
(T(2) * nearplane) / (right - left), T(0), (right + left) / (right - left), T(0),
T(0), (T(2) * nearplane) / (top - bottom), (top + bottom) / (top - bottom), T(0),
-T(0), -T(0), (farplane + nearplane) / (farplane - nearplane), (T(2) * farplane * nearplane) / (farplane - nearplane),
T(0), T(0), -T(1), T(0)
};
#else
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), (right + left) / (right - left), T(0),
T(0), (T(2) * nearplane) / (top - bottom), (top + bottom) / (top - bottom), T(0),
T(0), T(0), -(farplane + nearplane) / (farplane - nearplane), -(T(2) * farplane * nearplane) / (farplane - nearplane),
T(0), T(0), -T(1), T(0)
};
#endif
return r;
}
static RMatrix4<T> CreatePerspectiveProjection ( T fovy, T aspect, T nearplane, T farplane) {
T range = Mathema<T>::Tan(fovy / T(2)) * nearplane;
T left = -range * aspect;
T right = range * aspect;
T bottom = -range;
T top = range;
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), (right + left) / (right - left), T(0),
T(0), (T(2) * nearplane) / (top - bottom), (top + bottom) / (top - bottom), T(0),
-T(0), -T(0), (farplane + nearplane) / (farplane - nearplane), (T(2) * farplane * nearplane) / (farplane - nearplane),
T(0), T(0), -T(1), T(0)
};
#else
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), (right + left) / (right - left), T(0),
T(0), (T(2) * nearplane) / (top - bottom), (top + bottom) / (top - bottom), T(0),
T(0), T(0), -(farplane + nearplane) / (farplane - nearplane), -(T(2) * farplane * nearplane) / (farplane - nearplane),
T(0), T(0), -T(1), T(0)
};
#endif
return r;
}
static RMatrix4<T> CreatePerspectiveFoV ( T fov, T width, T height, T nearplane, T farplane) {
T rad = (T)Mathema<T>::Radians(fov);
T h = Mathema<T>::Cos(T(0.5) * rad) / Mathema<T>::Sin(T(0.5) * rad);
T w = h * height / width;
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
w, T(0), T(0), T(0),
T(0), h, T(0), T(0),
-T(0), -T(0), (farplane + nearplane) / (farplane - nearplane), (T(2) * farplane * nearplane) / (farplane - nearplane),
T(0), T(0), -T(1), T(0)
};
#else
RMatrix4<T> r = {
w, T(0), T(0), T(0),
T(0), h, T(0), T(0),
T(0), T(0), -(farplane + nearplane) / (farplane - nearplane), -T(1),
T(0), T(0), -(T(2) * farplane * nearplane) / (farplane - nearplane), T(0)
};
#endif
return r;
}
static RMatrix4<T> CreateInfinitePerspective (T fovy, T aspect, T nearplane) {
T range = Mathema<T>::Tan(fovy / T(2)) * nearplane;
T left = -range * aspect;
T right = range * aspect;
T bottom = -range;
T top = range;
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), T(0), T(0),
T(0), (T(2) * nearplane) / (top - bottom), T(0), T(0),
-T(0), -T(0), T(1), T(1),
T(0), T(0), -T(2) * nearplane, T(0)
};
#else
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), T(0), T(0),
T(0), (T(2) * nearplane) / (top - bottom), T(0), T(0),
T(0), T(0), -T(1), -T(1),
T(0), T(0), -T(2) * nearplane, T(0)
};
#endif
return r;
}
static RMatrix4<T> CreateInfinitePerspective2 (T fovy, T aspect, T nearplane) {
T range = Mathema<T>::Tan((fovy / T(2))) * nearplane;
T left = -range * aspect;
T right = range * aspect;
T bottom = -range;
T top = range;
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), T(0), T(0),
T(0), (T(2) * nearplane) / (top - bottom), T(0), T(0),
-T(0), -T(0), T(0.0001) + T(1), T(1),
T(0), T(0), (T(0.0001) - T(2)) * nearplane, T(0)
};
#else
RMatrix4<T> r = {
(T(2) * nearplane) / (right - left), T(0), T(0), T(0),
T(0), (T(2) * nearplane) / (top - bottom), T(0), T(0),
T(0), T(0), T(0.0001) - T(1), -T(1),
T(0), T(0), (T(0.0001) - T(2)) * nearplane, T(0)
};
#endif
return r;
}
static RMatrix4<T> CreateLookAt ( const TVector3<T>& eye, const TVector3<T>& center, const TVector3<T>& up) {
TVector3<T> f = TVector3<T>::Normalize(center - eye);
TVector3<T> u = TVector3<T>::Normalize(up);
TVector3<T> s = TVector3<T>::Normalize(f.Cross(u));
u = s.Cross(f);
#ifdef FURROVINECOORDINATESYSTEM_LEFTHANDED
RMatrix4<T> r = {
s.x, s.y, s.z, -s.Dot(eye),
u.x, u.y, u.z, -u.Dot(eye),
f.x, f.y, f.z, -f.Dot(eye),
T(0), T(0), T(0), T(1)
};
#else
RMatrix4<T> r = {
s.x, s.y, s.z, -s.Dot(eye),
u.x, u.y, u.z, -u.Dot(eye),
f.x, f.y, f.z, -f.Dot(eye),
T(0), T(0), T(0), T(1)
};
#endif
return r;
}
static RMatrix4<T> CreateShearX (T dyradians, T dzradians) {
dyradians = Mathema<T>::Tan(dyradians);
dzradians = Mathema<T>::Tan(dzradians);
RMatrix4<T> r = {
T(1), dyradians, dzradians, T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShearX (T radians) {
radians = Mathema<T>::Tan(radians);
RMatrix4<T> r = {
T(1), radians, radians, T(0),
T(0), T(1), T(0), T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShearY (T radians) {
radians = Mathema<T>::Tan(radians);
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
radians, T(1), radians, T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShearY (T dxradians, T dzradians) {
dxradians = Mathema<T>::Tan(dxradians);
dzradians = Mathema<T>::Tan(dzradians);
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
dxradians, T(1), dzradians, T(0),
T(0), T(0), T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShearZ (T radians) {
radians = Mathema<T>::Tan(radians);
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
radians, radians, T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShearZ (T dxradians, T dyradians) {
dxradians = Mathema<T>::Tan(dxradians);
dyradians = Mathema<T>::Tan(dyradians);
RMatrix4<T> r = {
T(1), T(0), T(0), T(0),
T(0), T(1), T(0), T(0),
dxradians, dyradians, T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShear (T xradians = T(0), T yradians = T(0), T zradians = T(0)) {
xradians = Mathema<T>::Tan(xradians);
yradians = Mathema<T>::Tan(yradians);
zradians = Mathema<T>::Tan(zradians);
RMatrix4<T> r = {
T(1), xradians, xradians, T(0),
yradians, T(1), yradians, T(0),
zradians, zradians, T(1), T(0),
T(0), T(0), T(0), T(1) };
return r;
}
static RMatrix4<T> CreateShear (const TVector3<T>& radians) {
return CreateShear(radians.x, radians.y, radians.z);
}
};
}
#endif /* FURROVINERMATRIX4_H */
I2lmbmRlZiBGVVJST1ZJTkVSTUFUUklYNF9ICiNkZWZpbmUgRlVSUk9WSU5FUk1BVFJJWDRfSAoKI2luY2x1ZGUgPEZ1cnJvdmluZSsrL0NvcmUuaD4KI2luY2x1ZGUgPEZ1cnJvdmluZSsrL1F1YXRlcm5pb24uaD4KCm5hbWVzcGFjZSBGdXJyb3ZpbmUgewogICAgCgl0ZW1wbGF0ZSA8dHlwZW5hbWUgVD4gc3RydWN0IFJNYXRyaXg0IHsKCXB1YmxpYzoKCgkJdW5pb24gewoKCQkJc3RydWN0IHsKI2lmZGVmIEZVUlJPVklORU1BVFJJWF9ST1dNQUpPUgoJCQkJVAltMTEsIG0xMiwgbTEzLCBtMTQsCgkJCQkJbTIxLCBtMjIsIG0yMywgbTI0LAoJCQkJCW0zMSwgbTMyLCBtMzMsIG0zNCwKCQkJCQltNDEsIG00MiwgbTQzLCBtNDQ7CiNlbHNlCgkJCQlUCW0xMSwgbTIxLCBtMzEsIG00MSwKCQkJCQltMTIsIG0yMiwgbTMyLCBtNDIsCgkJCQkJbTEzLCBtMjMsIG0zMywgbTQzLAoJCQkJCW0xNCwgbTI0LCBtMzQsIG00NDsKI2VuZGlmIC8qIEZVUlJPVklORU1BVFJJWF9ST1dNQUpPUiAqLwoJCQl9OwoKCQkJVCBtWzE2XTsKCgkJCXN0cnVjdCB7CgkJCQl0eXBlbmFtZSBNYXRyaXhUcmFpdHM8VD46OlRBcGk0IGFwaTsKCQkJfTsKCgkJCVJWZWN0b3I0PFQ+IHJvd3NbNF07CgkJfTsKCgkJUk1hdHJpeDQ8VD4mIFNldCAoIFQgeDExID0gVCgxKSwgVCB4MjEgPSBUKDApLCBUIHgzMSA9IFQoMCksIFQgeDQxID0gVCgwKSwKCQkJVCB4MTIgPSBUKDApLCBUIHgyMiA9IFQoMSksIFQgeDMyID0gVCgwKSwgVCB4NDIgPSBUKDApLAoJCQlUIHgxMyA9IFQoMCksIFQgeDIzID0gVCgwKSwgVCB4MzMgPSBUKDEpLCBUIHg0MyA9IFQoMCksCgkJCVQgeDE0ID0gVCgwKSwgVCB4MjQgPSBUKDApLCBUIHgzNCA9IFQoMCksIFQgeDQ0ID0gVCgxKSApIHsKCQkJCW0xMSA9IHgxMTsKCQkJCW0xMiA9IHgxMjsKCQkJCW0xMyA9IHgxMzsKCQkJCW0xNCA9IHgxNDsKCQkJCW0yMSA9IHgyMTsKCQkJCW0yMiA9IHgyMjsKCQkJCW0yMyA9IHgyMzsKCQkJCW0yNCA9IHgyNDsKCQkJCW0zMSA9IHgzMTsKCQkJCW0zMiA9IHgzMjsKCQkJCW0zMyA9IHgzMzsKCQkJCW0zNCA9IHgzNDsKCQkJCW00MSA9IHg0MTsKCQkJCW00MiA9IHg0MjsKCQkJCW00MyA9IHg0MzsKCQkJCW00NCA9IHg0NDsKCQkJCXJldHVybiAqdGhpczsKCQl9CgoJCVJNYXRyaXg0PFQ+JiBTZXQgKCBib29sIG1lbW9yZGVyLAoJCQlUIHgwMSwgVCB4MDIsIFQgeDAzLCBUIHgwNCwKCQkJVCB4MDUsIFQgeDA2LCBUIHgwNywgVCB4MDgsCgkJCVQgeDA5LCBUIHgxMCwgVCB4MTEsIFQgeDEyLAoJCQlUIHgxMywgVCB4MTQsIFQgeDE1LCBUIHgxNiApIHsKCQkJCW1bMF0gPSB4MDE7CgkJCQltWzFdID0geDAyOwoJCQkJbVsyXSA9IHgwMzsKCQkJCW1bM10gPSB4MDQ7CgkJCQltWzRdID0geDA1OwoJCQkJbVs1XSA9IHgwNjsKCQkJCW1bNl0gPSB4MDc7CgkJCQltWzddID0geDA4OwoJCQkJbVs4XSA9IHgwOTsKCQkJCW1bOV0gPSB4MTA7CgkJCQltWzEwXSA9IHgxMTsKCQkJCW1bMTFdID0geDEyOwoJCQkJbVsxMl0gPSB4MTM7CgkJCQltWzEzXSA9IHgxNDsKCQkJCW1bMTRdID0geDE1OwoJCQkJbVsxNV0gPSB4MTY7CgkJCQlyZXR1cm4gKnRoaXM7CgkJfQoKCQl2b2lkIElkZW50aWZ5ICgpIHsKCQkJbTEyID0gbTEzID0gbTE0ID0gbTIxID0gbTIzID0gbTI0ID0gbTMxID0gbTMyID0gbTM0ID0gbTQxID0gbTQyID0gbTQzID0gMDsKCQkJbTExID0gbTIyID0gbTMzID0gbTQ0ID0gKFQpMTsKCQl9CgoJCVJNYXRyaXg0PFQ+IENsb25lICgpIHsKCQkJUk1hdHJpeDQ8VD4gcjsKCQkJbWVtY3B5KG0sIHIubSwgc2l6ZW9mKFQpICogMTYpOwoJCQlyZXR1cm4gcjsKCQl9CgoJCVJNYXRyaXg0PFQ+JiBDbG9uZSAoY29uc3QgUk1hdHJpeDQ8VD4mIG9iaikgewoJCQltZW1jcHkobSwgb2JqLm0sIHNpemVvZihUKSAqIDE2KTsKCQkJcmV0dXJuICp0aGlzOwoJCX0KCgkJUk1hdHJpeDQ8VD4mIFRyYW5zcG9zZSAoKSB7CgkJCU1lbTo6U3dhcDxUPihtMTIsIG0yMSk7CgkJCU1lbTo6U3dhcDxUPihtMTMsIG0zMSk7CgkJCU1lbTo6U3dhcDxUPihtMTQsIG00MSk7CgoJCQlNZW06OlN3YXA8VD4obTMyLCBtMjMpOwoJCQlNZW06OlN3YXA8VD4obTM0LCBtNDMpOwoKCQkJTWVtOjpTd2FwPFQ+KG00MiwgbTI0KTsKCgkJCXJldHVybiAqdGhpczsKCQl9CgoJCVRWZWN0b3IzPFQ+IFRyYW5zZm9ybSAoY29uc3QgVFZlY3RvcjM8VD4mIHNvdXJjZSkgewoJCQlyZXR1cm4gKnRoaXMgKiBzb3VyY2U7CgkJfQoKCQlUVmVjdG9yNDxUPiBUcmFuc2Zvcm0gKGNvbnN0IFRWZWN0b3I0PFQ+JiBzb3VyY2UpIHsKCQkJcmV0dXJuICp0aGlzICogc291cmNlOwoJCX0KCgkJdm9pZCBUcmFuc2Zvcm0gKGNvbnN0IFRWZWN0b3IzPFQ+JiBzb3VyY2UsIFRWZWN0b3IzPFQ+JiBvdXQpIHsKCQkJVCB3ID0gbVs0ICogMSAtIDFdICogc291cmNlLnggKwoJCQkJbVs0ICogMiAtIDFdICogc291cmNlLnkgKwoJCQkJbVs0ICogMyAtIDFdICogc291cmNlLnogKwoJCQkJbVs0ICogNCAtIDFdOwoKCQkJb3V0LnggPSBtWzEgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzEgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzEgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzEgKiA0IC0gMV07CgkJCW91dC55ID0gbVsyICogMSAtIDFdICogc291cmNlLnggKwoJCQkJbVsyICogMiAtIDFdICogc291cmNlLnkgKwoJCQkJbVsyICogMyAtIDFdICogc291cmNlLnogKwoJCQkJbVsyICogNCAtIDFdOwoJCQlvdXQueiA9IG1bMyAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMyAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMyAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMyAqIDQgLSAxXTsKCgkJCW91dCAvPSB3OwoJCX0KCgkJdm9pZCBUcmFuc2Zvcm0gKGNvbnN0IFRWZWN0b3I0PFQ+JiBzb3VyY2UsIFRWZWN0b3I0PFQ+JiBvdXQpIHsKCQkJb3V0LnggPSBtWzEgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzEgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzEgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzEgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQkJb3V0LnkgPSBtWzIgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzIgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzIgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzIgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQkJb3V0LnogPSBtWzMgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzMgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzMgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzMgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQkJb3V0LncgPSBtWzQgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzQgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzQgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzQgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQl9CgoJCXZvaWQgVHJhbnNmb3JtIChjb25zdCBUVmVjdG9yNDxUPiYgc291cmNlLCBUVmVjdG9yMzxUPiYgb3V0KSB7CgkJCVQgdyA9IG1bNCAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bNCAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bNCAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bNCAqIDQgLSAxXSAqIHNvdXJjZS53OwoKCQkJb3V0LnggPSBtWzEgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzEgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzEgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzEgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQkJb3V0LnkgPSBtWzIgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzIgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzIgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzIgKiA0IC0gMV0gKiBzb3VyY2UudzsKCQkJb3V0LnogPSBtWzMgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzMgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzMgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzMgKiA0IC0gMV0gKiBzb3VyY2UudzsKCgkJCW91dCAvPSB3OwoJCX0KCgkJVFZlY3RvcjM8VD4gVHJhbnNmb3JtIChjb25zdCBUVmVjdG9yMzxUPiYgc291cmNlKSBjb25zdCB7CgkJCXJldHVybiAqdGhpcyAqIHNvdXJjZTsKCQl9CgoJCVRWZWN0b3I0PFQ+IFRyYW5zZm9ybSAoY29uc3QgVFZlY3RvcjQ8VD4mIHNvdXJjZSkgY29uc3QgewoJCQlyZXR1cm4gKnRoaXMgKiBzb3VyY2U7CgkJfQoKCQl2b2lkIFRyYW5zZm9ybSAoY29uc3QgVFZlY3RvcjM8VD4mIHNvdXJjZSwgVFZlY3RvcjM8VD4mIG91dCkgY29uc3QgewoJCQlUIHcgPSBtWzQgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzQgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzQgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzQgKiA0IC0gMV07CgoJCQlvdXQueCA9IG1bMSAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMSAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMSAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMSAqIDQgLSAxXTsKCQkJb3V0LnkgPSBtWzIgKiAxIC0gMV0gKiBzb3VyY2UueCArCgkJCQltWzIgKiAyIC0gMV0gKiBzb3VyY2UueSArCgkJCQltWzIgKiAzIC0gMV0gKiBzb3VyY2UueiArCgkJCQltWzIgKiA0IC0gMV07CgkJCW91dC56ID0gbVszICogMSAtIDFdICogc291cmNlLnggKwoJCQkJbVszICogMiAtIDFdICogc291cmNlLnkgKwoJCQkJbVszICogMyAtIDFdICogc291cmNlLnogKwoJCQkJbVszICogNCAtIDFdOwoKCQkJb3V0IC89IHc7CgkJfQoKCQl2b2lkIFRyYW5zZm9ybSAoY29uc3QgVFZlY3RvcjQ8VD4mIHNvdXJjZSwgVFZlY3RvcjQ8VD4mIG91dCkgY29uc3QgewoJCQlvdXQueCA9IG1bMSAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMSAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMSAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMSAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCQlvdXQueSA9IG1bMiAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMiAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMiAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMiAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCQlvdXQueiA9IG1bMyAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMyAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMyAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMyAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCQlvdXQudyA9IG1bNCAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bNCAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bNCAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bNCAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCX0KCgkJdm9pZCBUcmFuc2Zvcm0gKGNvbnN0IFRWZWN0b3I0PFQ+JiBzb3VyY2UsIFRWZWN0b3IzPFQ+JiBvdXQpIGNvbnN0IHsKCQkJVCB3ID0gbVs0ICogMSAtIDFdICogc291cmNlLnggKwoJCQkJbVs0ICogMiAtIDFdICogc291cmNlLnkgKwoJCQkJbVs0ICogMyAtIDFdICogc291cmNlLnogKwoJCQkJbVs0ICogNCAtIDFdICogc291cmNlLnc7CgoJCQlvdXQueCA9IG1bMSAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMSAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMSAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMSAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCQlvdXQueSA9IG1bMiAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMiAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMiAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMiAqIDQgLSAxXSAqIHNvdXJjZS53OwoJCQlvdXQueiA9IG1bMyAqIDEgLSAxXSAqIHNvdXJjZS54ICsKCQkJCW1bMyAqIDIgLSAxXSAqIHNvdXJjZS55ICsKCQkJCW1bMyAqIDMgLSAxXSAqIHNvdXJjZS56ICsKCQkJCW1bMyAqIDQgLSAxXSAqIHNvdXJjZS53OwoKCQkJb3V0IC89IHc7CgkJfQoKCQlUIERldGVybWluYW50ICgpIHsKCQkJVCBhMCA9IG1bMF0gKiBtWzVdIC0gbVsxXSAqIG1bNF07CgkJCVQgYTEgPSBtWzBdICogbVs2XSAtIG1bMl0gKiBtWzRdOwoJCQlUIGEyID0gbVswXSAqIG1bN10gLSBtWzNdICogbVs0XTsKCQkJVCBhMyA9IG1bMV0gKiBtWzZdIC0gbVsyXSAqIG1bNV07CgkJCVQgYTQgPSBtWzFdICogbVs3XSAtIG1bM10gKiBtWzVdOwoJCQlUIGE1ID0gbVsyXSAqIG1bN10gLSBtWzNdICogbVs2XTsKCQkJVCBiMCA9IG1bOF0gKiBtWzEzXSAtIG1bOV0gKiBtWzEyXTsKCQkJVCBiMSA9IG1bOF0gKiBtWzE0XSAtIG1bMTBdICogbVsxMl07CgkJCVQgYjIgPSBtWzhdICogbVsxNV0gLSBtWzExXSAqIG1bMTJdOwoJCQlUIGIzID0gbVs5XSAqIG1bMTRdIC0gbVsxMF0gKiBtWzEzXTsKCQkJVCBiNCA9IG1bOV0gKiBtWzE1XSAtIG1bMTFdICogbVsxM107CgkJCVQgYjUgPSBtWzEwXSAqIG1bMTVdIC0gbVsxMV0gKiBtWzE0XTsKCgkJCVQgZGV0ID0gYTAqYjUgLSBhMSpiNCArIGEyKmIzICsgYTMqYjIgLSBhNCpiMSArIGE1KmIwOwoKCQkJcmV0dXJuIGRldDsKCQl9CgoJCVJNYXRyaXg0PFQ+IEludmVyc2UgKCkgewoJCQlUIGEwID0gbVswXSAqIG1bNV0gLSBtWzFdICogbVs0XTsKCQkJVCBhMSA9IG1bMF0gKiBtWzZdIC0gbVsyXSAqIG1bNF07CgkJCVQgYTIgPSBtWzBdICogbVs3XSAtIG1bM10gKiBtWzRdOwoJCQlUIGEzID0gbVsxXSAqIG1bNl0gLSBtWzJdICogbVs1XTsKCQkJVCBhNCA9IG1bMV0gKiBtWzddIC0gbVszXSAqIG1bNV07CgkJCVQgYTUgPSBtWzJdICogbVs3XSAtIG1bM10gKiBtWzZdOwoJCQlUIGIwID0gbVs4XSAqIG1bMTNdIC0gbVs5XSAqIG1bMTJdOwoJCQlUIGIxID0gbVs4XSAqIG1bMTRdIC0gbVsxMF0gKiBtWzEyXTsKCQkJVCBiMiA9IG1bOF0gKiBtWzE1XSAtIG1bMTFdICogbVsxMl07CgkJCVQgYjMgPSBtWzldICogbVsxNF0gLSBtWzEwXSAqIG1bMTNdOwoJCQlUIGI0ID0gbVs5XSAqIG1bMTVdIC0gbVsxMV0gKiBtWzEzXTsKCQkJVCBiNSA9IG1bMTBdICogbVsxNV0gLSBtWzExXSAqIG1bMTRdOwoKCQkJVCBkZXQgPSBhMCAqIGI1IC0gYTEgKiBiNCArIGEyICogYjMgKyBhMyAqIGIyIC0gYTQgKiBiMSArIGE1ICogYjA7CgkJCVJNYXRyaXg0PFQ+IGludmVyc2U7CgkJCWlmIChNYXRoZW1hPFQ+OjpBYnMoZGV0KSA+IFQoMCkpIHsKCQkJCWludmVyc2UubVswXSA9ICsgbVs1XSAqIGI1IC0gbVs2XSAqIGI0ICsgbVs3XSAqIGIzOwoJCQkJaW52ZXJzZS5tWzRdID0gLSBtWzRdICogYjUgKyBtWzZdICogYjIgLSBtWzddICogYjE7CgkJCQlpbnZlcnNlLm1bOF0gPSArIG1bNF0gKiBiNCAtIG1bNV0gKiBiMiArIG1bN10gKiBiMDsKCQkJCWludmVyc2UubVsxMl0gPSAtIG1bNF0gKiBiMyArIG1bNV0gKiBiMSAtIG1bNl0gKiBiMDsKCQkJCWludmVyc2UubVsxXSA9IC0gbVsxXSAqIGI1ICsgbVsyXSAqIGI0IC0gbVszXSAqIGIzOwoJCQkJaW52ZXJzZS5tWzVdID0gKyBtWzBdICogYjUgLSBtWzJdICogYjIgKyBtWzNdICogYjE7CgkJCQlpbnZlcnNlLm1bOV0gPSAtIG1bMF0gKiBiNCArIG1bMV0gKiBiMiAtIG1bM10gKiBiMDsKCQkJCWludmVyc2UubVsxM10gPSArIG1bMF0gKiBiMyAtIG1bMV0gKiBiMSArIG1bMl0gKiBiMDsKCQkJCWludmVyc2UubVsyXSA9ICsgbVsxM10gKiBhNSAtIG1bMTRdICogYTQgKyBtWzE1XSAqIGEzOwoJCQkJaW52ZXJzZS5tWzZdID0gLSBtWzEyXSAqIGE1ICsgbVsxNF0gKiBhMiAtIG1bMTVdICogYTE7CgkJCQlpbnZlcnNlLm1bMTBdID0gKyBtWzEyXSAqIGE0IC0gbVsxM10gKiBhMiArIG1bMTVdICogYTA7CgkJCQlpbnZlcnNlLm1bMTRdID0gLSBtWzEyXSAqIGEzICsgbVsxM10gKiBhMSAtIG1bMTRdICogYTA7CgkJCQlpbnZlcnNlLm1bM10gPSAtIG1bOV0gKiBhNSArIG1bMTBdICogYTQgLSBtWzExXSAqIGEzOwoJCQkJaW52ZXJzZS5tWzddID0gKyBtWzhdICogYTUgLSBtWzEwXSAqIGEyICsgbVsxMV0gKiBhMTsKCQkJCWludmVyc2UubVsxMV0gPSAtIG1bOF0gKiBhNCArIG1bOV0gKiBhMiAtIG1bMTFdICogYTA7CgkJCQlpbnZlcnNlLm1bMTVdID0gKyBtWzhdICogYTMgLSBtWzldICogYTEgKyBtWzEwXSAqIGEwOwoKCQkJCVQgaW52RGV0ID0gKFQoMSkpIC8gZGV0OwoJCQkJaW52ZXJzZS5tWzBdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMV0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsyXSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzNdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bNF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVs1XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzZdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bN10gICo9IGludkRldDsKCQkJCWludmVyc2UubVs4XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzldICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTBdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTFdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTJdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTNdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTRdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bMTVdICAqPSBpbnZEZXQ7CgoJCQkJcmV0dXJuIGludmVyc2U7CgkJCX0KCQkJaW52ZXJzZS5JZGVudGlmeSgpOwoJCQlyZXR1cm4gaW52ZXJzZTsKCQl9CgoJCWJvb2wgSW52ZXJ0ICgpIHsKCQkJVCBhMCA9IG1bMF0gKiBtWzVdIC0gbVsxXSAqIG1bNF07CgkJCVQgYTEgPSBtWzBdICogbVs2XSAtIG1bMl0gKiBtWzRdOwoJCQlUIGEyID0gbVswXSAqIG1bN10gLSBtWzNdICogbVs0XTsKCQkJVCBhMyA9IG1bMV0gKiBtWzZdIC0gbVsyXSAqIG1bNV07CgkJCVQgYTQgPSBtWzFdICogbVs3XSAtIG1bM10gKiBtWzVdOwoJCQlUIGE1ID0gbVsyXSAqIG1bN10gLSBtWzNdICogbVs2XTsKCQkJVCBiMCA9IG1bOF0gKiBtWzEzXSAtIG1bOV0gKiBtWzEyXTsKCQkJVCBiMSA9IG1bOF0gKiBtWzE0XSAtIG1bMTBdICogbVsxMl07CgkJCVQgYjIgPSBtWzhdICogbVsxNV0gLSBtWzExXSAqIG1bMTJdOwoJCQlUIGIzID0gbVs5XSAqIG1bMTRdIC0gbVsxMF0gKiBtWzEzXTsKCQkJVCBiNCA9IG1bOV0gKiBtWzE1XSAtIG1bMTFdICogbVsxM107CgkJCVQgYjUgPSBtWzEwXSAqIG1bMTVdIC0gbVsxMV0gKiBtWzE0XTsKCgkJCVQgZGV0ID0gYTAgKiBiNSAtIGExICogYjQgKyBhMiAqIGIzICsgYTMgKiBiMiAtIGE0ICogYjEgKyBhNSAqIGIwOwoJCQlpZiAoTWF0aGVtYTxUPjo6QWJzKGRldCkgPiBUKDApKSB7CgkJCQlSTWF0cml4NDxUPiBpbnZlcnNlOwoJCQkJaW52ZXJzZS5tWzBdID0gKyBtWzVdICogYjUgLSBtWzZdICogYjQgKyBtWzddICogYjM7CgkJCQlpbnZlcnNlLm1bNF0gPSAtIG1bNF0gKiBiNSArIG1bNl0gKiBiMiAtIG1bN10gKiBiMTsKCQkJCWludmVyc2UubVs4XSA9ICsgbVs0XSAqIGI0IC0gbVs1XSAqIGIyICsgbVs3XSAqIGIwOwoJCQkJaW52ZXJzZS5tWzEyXSA9IC0gbVs0XSAqIGIzICsgbVs1XSAqIGIxIC0gbVs2XSAqIGIwOwoJCQkJaW52ZXJzZS5tWzFdID0gLSBtWzFdICogYjUgKyBtWzJdICogYjQgLSBtWzNdICogYjM7CgkJCQlpbnZlcnNlLm1bNV0gPSArIG1bMF0gKiBiNSAtIG1bMl0gKiBiMiArIG1bM10gKiBiMTsKCQkJCWludmVyc2UubVs5XSA9IC0gbVswXSAqIGI0ICsgbVsxXSAqIGIyIC0gbVszXSAqIGIwOwoJCQkJaW52ZXJzZS5tWzEzXSA9ICsgbVswXSAqIGIzIC0gbVsxXSAqIGIxICsgbVsyXSAqIGIwOwoJCQkJaW52ZXJzZS5tWzJdID0gKyBtWzEzXSAqIGE1IC0gbVsxNF0gKiBhNCArIG1bMTVdICogYTM7CgkJCQlpbnZlcnNlLm1bNl0gPSAtIG1bMTJdICogYTUgKyBtWzE0XSAqIGEyIC0gbVsxNV0gKiBhMTsKCQkJCWludmVyc2UubVsxMF0gPSArIG1bMTJdICogYTQgLSBtWzEzXSAqIGEyICsgbVsxNV0gKiBhMDsKCQkJCWludmVyc2UubVsxNF0gPSAtIG1bMTJdICogYTMgKyBtWzEzXSAqIGExIC0gbVsxNF0gKiBhMDsKCQkJCWludmVyc2UubVszXSA9IC0gbVs5XSAqIGE1ICsgbVsxMF0gKiBhNCAtIG1bMTFdICogYTM7CgkJCQlpbnZlcnNlLm1bN10gPSArIG1bOF0gKiBhNSAtIG1bMTBdICogYTIgKyBtWzExXSAqIGExOwoJCQkJaW52ZXJzZS5tWzExXSA9IC0gbVs4XSAqIGE0ICsgbVs5XSAqIGEyIC0gbVsxMV0gKiBhMDsKCQkJCWludmVyc2UubVsxNV0gPSArIG1bOF0gKiBhMyAtIG1bOV0gKiBhMSArIG1bMTBdICogYTA7CgoJCQkJVCBpbnZEZXQgPSAoVCgxKSkgLyBkZXQ7CgkJCQlpbnZlcnNlLm1bMF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxXSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzJdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bM10gICo9IGludkRldDsKCQkJCWludmVyc2UubVs0XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzVdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bNl0gICo9IGludkRldDsKCQkJCWludmVyc2UubVs3XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzhdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bOV0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMV0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMl0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxM10gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxNF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxNV0gICo9IGludkRldDsKCgkJCQlDbG9uZShpbnZlcnNlKTsKCgkJCQlyZXR1cm4gdHJ1ZTsKCQkJfQoKCQkJcmV0dXJuIGZhbHNlOwoJCX0KCgkJdm9pZCBEZWNvbXBvc2UgKFRWZWN0b3IzPFQ+JiBvdXRzY2FsZSwgVFF1YXRlcm5pb248VD4mIG91dHJvdGF0ZSwgVFZlY3RvcjM8VD4mIG91dHRyYW5zbGF0aW9uKSB7CgkJCVQgbWRpYWcgPSBNYXRoZW1hPFQ+OjpTcXJ0KG1bMF0gKyBtWzVdICsgbVsxMF0gKyBtWzE1XSk7CgkJCVQgbWRpYWcyID0gMiAqIG1kaWFnOwojaWZkZWYgRlVSUk9WSU5FTUFUUklYX1JPV01BSk9SCgkJCW91dHNjYWxlLnggPSBNYXRoZW1hPFQ+OjpTcXJ0KG0xMSAqIG0xMSArIG0yMSAqIG0yMSAqIG0zMSAqIG0zMSk7CgkJCW91dHNjYWxlLnkgPSBNYXRoZW1hPFQ+OjpTcXJ0KG0xMiAqIG0xMiArIG0yMiAqIG0yMiAqIG0zMiAqIG0zMik7CgkJCW91dHNjYWxlLnogPSBNYXRoZW1hPFQ+OjpTcXJ0KG0xMyAqIG0xMyArIG0yMyAqIG0yMyAqIG0zMyAqIG0zMyk7CgkJCW91dHRyYW5zbGF0aW9uLnggPSBtMTQ7CgkJCW91dHRyYW5zbGF0aW9uLnkgPSBtMjQ7CgkJCW91dHRyYW5zbGF0aW9uLnogPSBtMzQ7CgkJCW91dHJvdGF0ZS54ID0gKG1bNl0gLSBtWzldKSAvIG1kaWFnMjsKCQkJb3V0cm90YXRlLnkgPSAobVs4XSAtIG1bMl0pIC8gbWRpYWcyOwoJCQlvdXRyb3RhdGUueiA9IChtWzFdIC0gbVs0XSkgLyBtZGlhZzI7CgkJCW91dHJvdGF0ZS53ID0gbWRpYWcgLyAyOwojZWxzZQoJCQlvdXR0cmFuc2xhdGlvbi54ID0gbVszXTsKCQkJb3V0dHJhbnNsYXRpb24ueSA9IG1bN107CgkJCW91dHRyYW5zbGF0aW9uLnogPSBtWzExXTsKCQkJb3V0c2NhbGUueCA9IE1hdGhlbWE8VD46OlNxcnQobVswXSAqIG1bMF0gKyBtWzFdICogbVsxXSArIG1bMl0gKiBtWzJdKTsKCQkJb3V0c2NhbGUueSA9IE1hdGhlbWE8VD46OlNxcnQobVs0XSAqIG1bNF0gKyBtWzVdICogbVs1XSArIG1bNl0gKiBtWzZdKTsKCQkJb3V0c2NhbGUueiA9IE1hdGhlbWE8VD46OlNxcnQobVs4XSAqIG1bOF0gKyBtWzldICogbVs5XSArIG1bMTBdICogbVsxMF0pOwoJCQlvdXRyb3RhdGUueCA9IChtWzZdIC0gbVs5XSkgLyBtZGlhZzI7CgkJCW91dHJvdGF0ZS55ID0gKG1bOF0gLSBtWzJdKSAvIG1kaWFnMjsKCQkJb3V0cm90YXRlLnogPSAobVsxXSAtIG1bNF0pIC8gbWRpYWcyOwoJCQlvdXRyb3RhdGUudyA9IG1kaWFnIC8gMjsKI2VuZGlmCgkJfQoKCQl2b2lkIERlY29tcG9zZSAoVFZlY3RvcjM8VD4mIG91dHNjYWxlLCBUVmVjdG9yMzxUPiYgb3V0cm90YXRlLCBUVmVjdG9yMzxUPiYgb3VUcmFuc2xhdGUpIHsKI2lmZGVmIEZVUlJPVklORU1BVFJJWF9ST1dNQUpPUgoJCQlvdXRzY2FsZS54ID0gTWF0aGVtYTxUPjo6U3FydChtMTEgKiBtMTEgKyBtMjEgKiBtMjEgKiBtMzEgKiBtMzEpOwoJCQlvdXRzY2FsZS55ID0gTWF0aGVtYTxUPjo6U3FydChtMTIgKiBtMTIgKyBtMjIgKiBtMjIgKiBtMzIgKiBtMzIpOwoJCQlvdXRzY2FsZS56ID0gTWF0aGVtYTxUPjo6U3FydChtMTMgKiBtMTMgKyBtMjMgKiBtMjMgKiBtMzMgKiBtMzMpOwoJCQlvdVRyYW5zbGF0ZS54ID0gbTE0OwoJCQlvdVRyYW5zbGF0ZS55ID0gbTI0OwoJCQlvdVRyYW5zbGF0ZS56ID0gbTM0OwoJCQlvdXRyb3RhdGUueCA9IChtWzZdIC0gbVs5XSkgLyBtZGlhZzI7CgkJCW91dHJvdGF0ZS55ID0gKG1bOF0gLSBtWzJdKSAvIG1kaWFnMjsKCQkJb3V0cm90YXRlLnogPSAobVsxXSAtIG1bNF0pIC8gbWRpYWcyOwoJCQlvdXRyb3RhdGUudyA9IG1kaWFnIC8gMjsKI2Vsc2UKCQkJb3VUcmFuc2xhdGUueCA9IG1bM107CgkJCW91VHJhbnNsYXRlLnkgPSBtWzddOwoJCQlvdVRyYW5zbGF0ZS56ID0gbVsxMV07CgkJCW91dHNjYWxlLnggPSBNYXRoZW1hPFQ+OjpTcXJ0KG1bMF0gKiBtWzBdICsgbVsxXSAqIG1bMV0gKyBtWzJdICogbVsyXSk7CgkJCW91dHNjYWxlLnkgPSBNYXRoZW1hPFQ+OjpTcXJ0KG1bNF0gKiBtWzRdICsgbVs1XSAqIG1bNV0gKyBtWzZdICogbVs2XSk7CgkJCW91dHNjYWxlLnogPSBNYXRoZW1hPFQ+OjpTcXJ0KG1bOF0gKiBtWzhdICsgbVs5XSAqIG1bOV0gKyBtWzEwXSAqIG1bMTBdKTsKCQkJb3V0cm90YXRlLnkgPSBNYXRoZW1hPFQ+OjpBc2luKC1tWzhdKTsKCQkJVCB0aGV0YSA9IE1hdGhlbWE8VD46OkNvcyhvdXRyb3RhdGUueSk7CgkJCW91dHJvdGF0ZS54ID0gTWF0aGVtYTxUPjo6QXNpbihNYXRoZW1hPFQ+OjpNb2QobVs5XSAvIHRoZXRhLCBUKDEpKSApOwoJCQlvdXRyb3RhdGUueiA9IE1hdGhlbWE8VD46OkFzaW4oTWF0aGVtYTxUPjo6TW9kKG1bNF0gLyB0aGV0YSwgVCgxKSkgKTsKI2VuZGlmCgkJfQoKCQlSTWF0cml4NDxUPiBvcGVyYXRvcisgKGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCkgY29uc3QgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJbVswXSArIHJpZ2h0Lm1bMF0sCgkJCQltWzFdICsgcmlnaHQubVsxXSwKCQkJCW1bMl0gKyByaWdodC5tWzJdLAoJCQkJbVszXSArIHJpZ2h0Lm1bM10sCgkJCQltWzRdICsgcmlnaHQubVs0XSwKCQkJCW1bNV0gKyByaWdodC5tWzVdLAoJCQkJbVs2XSArIHJpZ2h0Lm1bNl0sCgkJCQltWzddICsgcmlnaHQubVs3XSwKCQkJCW1bOF0gKyByaWdodC5tWzhdLAoJCQkJbVs5XSArIHJpZ2h0Lm1bOV0sCgkJCQltWzEwXSArIHJpZ2h0Lm1bMTBdLAoJCQkJbVsxMV0gKyByaWdodC5tWzExXSwKCQkJCW1bMTJdICsgcmlnaHQubVsxMl0sCgkJCQltWzEzXSArIHJpZ2h0Lm1bMTNdLAoJCQkJbVsxNF0gKyByaWdodC5tWzE0XSwKCQkJCW1bMTVdICsgcmlnaHQubVsxNV0KCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlSTWF0cml4NDxUPiBvcGVyYXRvci0gKGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCkgY29uc3QgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJbVswXSAtIHJpZ2h0Lm1bMF0sCgkJCQltWzFdIC0gcmlnaHQubVsxXSwKCQkJCW1bMl0gLSByaWdodC5tWzJdLAoJCQkJbVszXSAtIHJpZ2h0Lm1bM10sCgkJCQltWzRdIC0gcmlnaHQubVs0XSwKCQkJCW1bNV0gLSByaWdodC5tWzVdLAoJCQkJbVs2XSAtIHJpZ2h0Lm1bNl0sCgkJCQltWzddIC0gcmlnaHQubVs3XSwKCQkJCW1bOF0gLSByaWdodC5tWzhdLAoJCQkJbVs5XSAtIHJpZ2h0Lm1bOV0sCgkJCQltWzEwXSAtIHJpZ2h0Lm1bMTBdLAoJCQkJbVsxMV0gLSByaWdodC5tWzExXSwKCQkJCW1bMTJdIC0gcmlnaHQubVsxMl0sCgkJCQltWzEzXSAtIHJpZ2h0Lm1bMTNdLAoJCQkJbVsxNF0gLSByaWdodC5tWzE0XSwKCQkJCW1bMTVdIC0gcmlnaHQubVsxNV0KCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlSTWF0cml4NDxUPiBvcGVyYXRvciogKGNvbnN0IFQmIHJpZ2h0KSBjb25zdCB7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQltWzBdICogcmlnaHQsCgkJCQltWzFdICogcmlnaHQsCgkJCQltWzJdICogcmlnaHQsCgkJCQltWzNdICogcmlnaHQsCgkJCQltWzRdICogcmlnaHQsCgkJCQltWzVdICogcmlnaHQsCgkJCQltWzZdICogcmlnaHQsCgkJCQltWzddICogcmlnaHQsCgkJCQltWzhdICogcmlnaHQsCgkJCQltWzldICogcmlnaHQsCgkJCQltWzEwXSAqIHJpZ2h0LAoJCQkJbVsxMV0gKiByaWdodCwKCQkJCW1bMTJdICogcmlnaHQsCgkJCQltWzEzXSAqIHJpZ2h0LAoJCQkJbVsxNF0gKiByaWdodCwKCQkJCW1bMTVdICogcmlnaHQKCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlSTWF0cml4NDxUPiBvcGVyYXRvci8gKGNvbnN0IFQmIHJpZ2h0KSBjb25zdCB7CgkJCWlmIChyaWdodCA9PSBUKDApKSB7CgkJCQlSTWF0cml4NDxUPiB6ID0geyAwIH07CgkJCQlyZXR1cm4gejsKCQkJfQoJCQlUIGludnJpZ2h0ID0gKFQoMSkpIC8gcmlnaHQ7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7IAoJCQkJbVswXSAqIGludnJpZ2h0LAoJCQkJbVsxXSAqIGludnJpZ2h0LAoJCQkJbVsyXSAqIGludnJpZ2h0LAoJCQkJbVszXSAqIGludnJpZ2h0LAoJCQkJbVs0XSAqIGludnJpZ2h0LAoJCQkJbVs1XSAqIGludnJpZ2h0LAoJCQkJbVs2XSAqIGludnJpZ2h0LAoJCQkJbVs3XSAqIGludnJpZ2h0LAoJCQkJbVs4XSAqIGludnJpZ2h0LAoJCQkJbVs5XSAqIGludnJpZ2h0LAoJCQkJbVsxMF0gKiBpbnZyaWdodCwKCQkJCW1bMTFdICogaW52cmlnaHQsCgkJCQltWzEyXSAqIGludnJpZ2h0LAoJCQkJbVsxM10gKiBpbnZyaWdodCwKCQkJCW1bMTRdICogaW52cmlnaHQsCgkJCQltWzE1XSAqIGludnJpZ2h0IH07CgoJCQlyZXR1cm4gcjsKCQl9CgoJCVJNYXRyaXg0PFQ+JiBvcGVyYXRvcis9IChjb25zdCBSTWF0cml4NDxUPiYgcmlnaHQpIHsKCQkJbVswXSArPSByaWdodC5tWzBdOwoJCQltWzFdICs9IHJpZ2h0Lm1bMV07CgkJCW1bMl0gKz0gcmlnaHQubVsyXTsKCQkJbVszXSArPSByaWdodC5tWzNdOwoJCQltWzRdICs9IHJpZ2h0Lm1bNF07CgkJCW1bNV0gKz0gcmlnaHQubVs1XTsKCQkJbVs2XSArPSByaWdodC5tWzZdOwoJCQltWzddICs9IHJpZ2h0Lm1bN107CgkJCW1bOF0gKz0gcmlnaHQubVs4XTsKCQkJbVs5XSArPSByaWdodC5tWzldOwoJCQltWzEwXSArPSByaWdodC5tWzEwXTsKCQkJbVsxMV0gKz0gcmlnaHQubVsxMV07CgkJCW1bMTJdICs9IHJpZ2h0Lm1bMTJdOwoJCQltWzEzXSArPSByaWdodC5tWzEzXTsKCQkJbVsxNF0gKz0gcmlnaHQubVsxNF07CgkJCW1bMTVdICs9IHJpZ2h0Lm1bMTVdOwoKCQkJcmV0dXJuICp0aGlzOwoJCX0KCgkJUk1hdHJpeDQ8VD4mIG9wZXJhdG9yLT0gKGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCkgewoJCQltWzBdIC09IHJpZ2h0Lm1bMF07CgkJCW1bMV0gLT0gcmlnaHQubVsxXTsKCQkJbVsyXSAtPSByaWdodC5tWzJdOwoJCQltWzNdIC09IHJpZ2h0Lm1bM107CgkJCW1bNF0gLT0gcmlnaHQubVs0XTsKCQkJbVs1XSAtPSByaWdodC5tWzVdOwoJCQltWzZdIC09IHJpZ2h0Lm1bNl07CgkJCW1bN10gLT0gcmlnaHQubVs3XTsKCQkJbVs4XSAtPSByaWdodC5tWzhdOwoJCQltWzldIC09IHJpZ2h0Lm1bOV07CgkJCW1bMTBdIC09IHJpZ2h0Lm1bMTBdOwoJCQltWzExXSAtPSByaWdodC5tWzExXTsKCQkJbVsxMl0gLT0gcmlnaHQubVsxMl07CgkJCW1bMTNdIC09IHJpZ2h0Lm1bMTNdOwoJCQltWzE0XSAtPSByaWdodC5tWzE0XTsKCQkJbVsxNV0gLT0gcmlnaHQubVsxNV07CgoJCQlyZXR1cm4gKnRoaXM7CgkJfQoKCQlSTWF0cml4NDxUPiYgb3BlcmF0b3IqPSAoY29uc3QgVCYgcmlnaHQpIHsKCQkJbVswXSAqPSByaWdodDsKCQkJbVsxXSAqPSByaWdodDsKCQkJbVsyXSAqPSByaWdodDsKCQkJbVszXSAqPSByaWdodDsKCQkJbVs0XSAqPSByaWdodDsKCQkJbVs1XSAqPSByaWdodDsKCQkJbVs2XSAqPSByaWdodDsKCQkJbVs3XSAqPSByaWdodDsKCQkJbVs4XSAqPSByaWdodDsKCQkJbVs5XSAqPSByaWdodDsKCQkJbVsxMF0gKj0gcmlnaHQ7CgkJCW1bMTFdICo9IHJpZ2h0OwoJCQltWzEyXSAqPSByaWdodDsKCQkJbVsxM10gKj0gcmlnaHQ7CgkJCW1bMTRdICo9IHJpZ2h0OwoJCQltWzE1XSAqPSByaWdodDsKCgkJCXJldHVybiAqdGhpczsKCQl9CgoJCVJNYXRyaXg0PFQ+JiBvcGVyYXRvci89IChjb25zdCBUJiByaWdodCkgewoJCQlpZiAocmlnaHQgPT0gVCgwKSkKCQkJCXJldHVybiAqdGhpczsKCgkJCVQgaW52cmlnaHQgPSAoVCgxKSkgLyByaWdodDsKCQkJbVswXSAqPSBpbnZyaWdodDsKCQkJbVsxXSAqPSBpbnZyaWdodDsKCQkJbVsyXSAqPSBpbnZyaWdodDsKCQkJbVszXSAqPSBpbnZyaWdodDsKCQkJbVs0XSAqPSBpbnZyaWdodDsKCQkJbVs1XSAqPSBpbnZyaWdodDsKCQkJbVs2XSAqPSBpbnZyaWdodDsKCQkJbVs3XSAqPSBpbnZyaWdodDsKCQkJbVs4XSAqPSBpbnZyaWdodDsKCQkJbVs5XSAqPSBpbnZyaWdodDsKCQkJbVsxMF0gKj0gaW52cmlnaHQ7CgkJCW1bMTFdICo9IGludnJpZ2h0OwoJCQltWzEyXSAqPSBpbnZyaWdodDsKCQkJbVsxM10gKj0gaW52cmlnaHQ7CgkJCW1bMTRdICo9IGludnJpZ2h0OwoJCQltWzE1XSAqPSBpbnZyaWdodDsKCgkJCXJldHVybiAqdGhpczsKCQl9CgoJCVRWZWN0b3I0PFQ+IG9wZXJhdG9yKiAoIGNvbnN0IFRWZWN0b3I0PFQ+JiByaWdodCApIHsKCQkJcmV0dXJuIFRWZWN0b3I0PFQ+KAoJCQkJbVsxICogMSAtIDFdICogcmlnaHQueCArCgkJCQltWzEgKiAyIC0gMV0gKiByaWdodC55ICsKCQkJCW1bMSAqIDMgLSAxXSAqIHJpZ2h0LnogKwoJCQkJbVsxICogNCAtIDFdICogcmlnaHQudywKCgkJCQltWzIgKiAxIC0gMV0gKiByaWdodC54ICsKCQkJCW1bMiAqIDIgLSAxXSAqIHJpZ2h0LnkgKwoJCQkJbVsyICogMyAtIDFdICogcmlnaHQueiArCgkJCQltWzIgKiA0IC0gMV0gKiByaWdodC53LAoKCQkJCW1bMyAqIDEgLSAxXSAqIHJpZ2h0LnggKwoJCQkJbVszICogMiAtIDFdICogcmlnaHQueSArCgkJCQltWzMgKiAzIC0gMV0gKiByaWdodC56ICsKCQkJCW1bMyAqIDQgLSAxXSAqIHJpZ2h0LncsCgoJCQkJbVs0ICogMSAtIDFdICogcmlnaHQueCArCgkJCQltWzQgKiAyIC0gMV0gKiByaWdodC55ICsKCQkJCW1bNCAqIDMgLSAxXSAqIHJpZ2h0LnogKwoJCQkJbVs0ICogNCAtIDFdICogcmlnaHQudwoJCQkJKTsKCQl9CgoJCVRWZWN0b3IzPFQ+IG9wZXJhdG9yKiAoIGNvbnN0IFRWZWN0b3IzPFQ+JiByaWdodCApIHsKCQkJcmV0dXJuIFRWZWN0b3IzPFQ+ICgKCQkJCW1bMSAqIDEgLSAxXSAqIHJpZ2h0LnggKwoJCQkJbVsxICogMiAtIDFdICogcmlnaHQueSArCgkJCQltWzEgKiAzIC0gMV0gKiByaWdodC56ICsKCQkJCW1bMSAqIDQgLSAxXSwKCgkJCQltWzIgKiAxIC0gMV0gKiByaWdodC54ICsKCQkJCW1bMiAqIDIgLSAxXSAqIHJpZ2h0LnkgKwoJCQkJbVsyICogMyAtIDFdICogcmlnaHQueiArCgkJCQltWzIgKiA0IC0gMV0sCgoJCQkJbVszICogMSAtIDFdICogcmlnaHQueCArCgkJCQltWzMgKiAyIC0gMV0gKiByaWdodC55ICsKCQkJCW1bMyAqIDMgLSAxXSAqIHJpZ2h0LnogKwoJCQkJbVszICogNCAtIDFdLAoKCQkJCW1bNCAqIDEgLSAxXSAqIHJpZ2h0LnggKwoJCQkJbVs0ICogMiAtIDFdICogcmlnaHQueSArCgkJCQltWzQgKiAzIC0gMV0gKiByaWdodC56ICsKCQkJCW1bNCAqIDQgLSAxXQoJCQkpOwoJCX0KCgkJUk1hdHJpeDQ8VD4gb3BlcmF0b3IqICggY29uc3QgUk1hdHJpeDQ8VD4mIHJpZ2h0ICkgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJKHJpZ2h0Lm1bMSAqIDEgLSAxXSAqIG1bMSAqIDEgLSAxXSArIHJpZ2h0Lm1bMSAqIDIgLSAxXSAqIG1bMiAqIDEgLSAxXSArIHJpZ2h0Lm1bMSAqIDMgLSAxXSAqIG1bMyAqIDEgLSAxXSArIHJpZ2h0Lm1bMSAqIDQgLSAxXSAqIG1bNCAqIDEgLSAxXSksCgkJCQkocmlnaHQubVsxICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVsxICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVsxICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVsxICogNCAtIDFdICogbVs0ICogMiAtIDFdKSwKCQkJCShyaWdodC5tWzEgKiAxIC0gMV0gKiBtWzEgKiAzIC0gMV0gKyByaWdodC5tWzEgKiAyIC0gMV0gKiBtWzIgKiAzIC0gMV0gKyByaWdodC5tWzEgKiAzIC0gMV0gKiBtWzMgKiAzIC0gMV0gKyByaWdodC5tWzEgKiA0IC0gMV0gKiBtWzQgKiAzIC0gMV0pLAoJCQkJKHJpZ2h0Lm1bMSAqIDEgLSAxXSAqIG1bMSAqIDQgLSAxXSArIHJpZ2h0Lm1bMSAqIDIgLSAxXSAqIG1bMiAqIDQgLSAxXSArIHJpZ2h0Lm1bMSAqIDMgLSAxXSAqIG1bMyAqIDQgLSAxXSArIHJpZ2h0Lm1bMSAqIDQgLSAxXSAqIG1bNCAqIDQgLSAxXSksCgkJCQkocmlnaHQubVsyICogMSAtIDFdICogbVsxICogMSAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogMSAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogMSAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogMSAtIDFdKSwKCQkJCShyaWdodC5tWzIgKiAxIC0gMV0gKiBtWzEgKiAyIC0gMV0gKyByaWdodC5tWzIgKiAyIC0gMV0gKiBtWzIgKiAyIC0gMV0gKyByaWdodC5tWzIgKiAzIC0gMV0gKiBtWzMgKiAyIC0gMV0gKyByaWdodC5tWzIgKiA0IC0gMV0gKiBtWzQgKiAyIC0gMV0pLAoJCQkJKHJpZ2h0Lm1bMiAqIDEgLSAxXSAqIG1bMSAqIDMgLSAxXSArIHJpZ2h0Lm1bMiAqIDIgLSAxXSAqIG1bMiAqIDMgLSAxXSArIHJpZ2h0Lm1bMiAqIDMgLSAxXSAqIG1bMyAqIDMgLSAxXSArIHJpZ2h0Lm1bMiAqIDQgLSAxXSAqIG1bNCAqIDMgLSAxXSksCgkJCQkocmlnaHQubVsyICogMSAtIDFdICogbVsxICogNCAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogNCAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogNCAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogNCAtIDFdKSwKCQkJCShyaWdodC5tWzMgKiAxIC0gMV0gKiBtWzEgKiAxIC0gMV0gKyByaWdodC5tWzMgKiAyIC0gMV0gKiBtWzIgKiAxIC0gMV0gKyByaWdodC5tWzMgKiAzIC0gMV0gKiBtWzMgKiAxIC0gMV0gKyByaWdodC5tWzMgKiA0IC0gMV0gKiBtWzQgKiAxIC0gMV0pLAoJCQkJKHJpZ2h0Lm1bMyAqIDEgLSAxXSAqIG1bMSAqIDIgLSAxXSArIHJpZ2h0Lm1bMyAqIDIgLSAxXSAqIG1bMiAqIDIgLSAxXSArIHJpZ2h0Lm1bMyAqIDMgLSAxXSAqIG1bMyAqIDIgLSAxXSArIHJpZ2h0Lm1bMyAqIDQgLSAxXSAqIG1bNCAqIDIgLSAxXSksCgkJCQkocmlnaHQubVszICogMSAtIDFdICogbVsxICogMyAtIDFdICsgcmlnaHQubVszICogMiAtIDFdICogbVsyICogMyAtIDFdICsgcmlnaHQubVszICogMyAtIDFdICogbVszICogMyAtIDFdICsgcmlnaHQubVszICogNCAtIDFdICogbVs0ICogMyAtIDFdKSwKCQkJCShyaWdodC5tWzMgKiAxIC0gMV0gKiBtWzEgKiA0IC0gMV0gKyByaWdodC5tWzMgKiAyIC0gMV0gKiBtWzIgKiA0IC0gMV0gKyByaWdodC5tWzMgKiAzIC0gMV0gKiBtWzMgKiA0IC0gMV0gKyByaWdodC5tWzMgKiA0IC0gMV0gKiBtWzQgKiA0IC0gMV0pLAoJCQkJKHJpZ2h0Lm1bNCAqIDEgLSAxXSAqIG1bMSAqIDEgLSAxXSArIHJpZ2h0Lm1bNCAqIDIgLSAxXSAqIG1bMiAqIDEgLSAxXSArIHJpZ2h0Lm1bNCAqIDMgLSAxXSAqIG1bMyAqIDEgLSAxXSArIHJpZ2h0Lm1bNCAqIDQgLSAxXSAqIG1bNCAqIDEgLSAxXSksCgkJCQkocmlnaHQubVs0ICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVs0ICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVs0ICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVs0ICogNCAtIDFdICogbVs0ICogMiAtIDFdKSwKCQkJCShyaWdodC5tWzQgKiAxIC0gMV0gKiBtWzEgKiAzIC0gMV0gKyByaWdodC5tWzQgKiAyIC0gMV0gKiBtWzIgKiAzIC0gMV0gKyByaWdodC5tWzQgKiAzIC0gMV0gKiBtWzMgKiAzIC0gMV0gKyByaWdodC5tWzQgKiA0IC0gMV0gKiBtWzQgKiAzIC0gMV0pLAoJCQkJKHJpZ2h0Lm1bNCAqIDEgLSAxXSAqIG1bMSAqIDQgLSAxXSArIHJpZ2h0Lm1bNCAqIDIgLSAxXSAqIG1bMiAqIDQgLSAxXSArIHJpZ2h0Lm1bNCAqIDMgLSAxXSAqIG1bMyAqIDQgLSAxXSArIHJpZ2h0Lm1bNCAqIDQgLSAxXSAqIG1bNCAqIDQgLSAxXSkKCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlSTWF0cml4NDxUPiYgb3BlcmF0b3IqPSAoIGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCApIHsKCQkJVCBvdXRbMTZdID0gewoJCQkJcmlnaHQubVsxICogMSAtIDFdICogbVsxICogMSAtIDFdICsgcmlnaHQubVsxICogMiAtIDFdICogbVsyICogMSAtIDFdICsgcmlnaHQubVsxICogMyAtIDFdICogbVszICogMSAtIDFdICsgcmlnaHQubVsxICogNCAtIDFdICogbVs0ICogMSAtIDFdLAoJCQkJcmlnaHQubVsxICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVsxICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVsxICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVsxICogNCAtIDFdICogbVs0ICogMiAtIDFdLAoJCQkJcmlnaHQubVsxICogMSAtIDFdICogbVsxICogMyAtIDFdICsgcmlnaHQubVsxICogMiAtIDFdICogbVsyICogMyAtIDFdICsgcmlnaHQubVsxICogMyAtIDFdICogbVszICogMyAtIDFdICsgcmlnaHQubVsxICogNCAtIDFdICogbVs0ICogMyAtIDFdLAoJCQkJcmlnaHQubVsxICogMSAtIDFdICogbVsxICogNCAtIDFdICsgcmlnaHQubVsxICogMiAtIDFdICogbVsyICogNCAtIDFdICsgcmlnaHQubVsxICogMyAtIDFdICogbVszICogNCAtIDFdICsgcmlnaHQubVsxICogNCAtIDFdICogbVs0ICogNCAtIDFdLAoJCQkJcmlnaHQubVsyICogMSAtIDFdICogbVsxICogMSAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogMSAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogMSAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogMSAtIDFdLAoJCQkJcmlnaHQubVsyICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogMiAtIDFdLAoJCQkJcmlnaHQubVsyICogMSAtIDFdICogbVsxICogMyAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogMyAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogMyAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogMyAtIDFdLAoJCQkJcmlnaHQubVsyICogMSAtIDFdICogbVsxICogNCAtIDFdICsgcmlnaHQubVsyICogMiAtIDFdICogbVsyICogNCAtIDFdICsgcmlnaHQubVsyICogMyAtIDFdICogbVszICogNCAtIDFdICsgcmlnaHQubVsyICogNCAtIDFdICogbVs0ICogNCAtIDFdLAoJCQkJcmlnaHQubVszICogMSAtIDFdICogbVsxICogMSAtIDFdICsgcmlnaHQubVszICogMiAtIDFdICogbVsyICogMSAtIDFdICsgcmlnaHQubVszICogMyAtIDFdICogbVszICogMSAtIDFdICsgcmlnaHQubVszICogNCAtIDFdICogbVs0ICogMSAtIDFdLAoJCQkJcmlnaHQubVszICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVszICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVszICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVszICogNCAtIDFdICogbVs0ICogMiAtIDFdLAoJCQkJcmlnaHQubVszICogMSAtIDFdICogbVsxICogMyAtIDFdICsgcmlnaHQubVszICogMiAtIDFdICogbVsyICogMyAtIDFdICsgcmlnaHQubVszICogMyAtIDFdICogbVszICogMyAtIDFdICsgcmlnaHQubVszICogNCAtIDFdICogbVs0ICogMyAtIDFdLAoJCQkJcmlnaHQubVszICogMSAtIDFdICogbVsxICogNCAtIDFdICsgcmlnaHQubVszICogMiAtIDFdICogbVsyICogNCAtIDFdICsgcmlnaHQubVszICogMyAtIDFdICogbVszICogNCAtIDFdICsgcmlnaHQubVszICogNCAtIDFdICogbVs0ICogNCAtIDFdLAoJCQkJcmlnaHQubVs0ICogMSAtIDFdICogbVsxICogMSAtIDFdICsgcmlnaHQubVs0ICogMiAtIDFdICogbVsyICogMSAtIDFdICsgcmlnaHQubVs0ICogMyAtIDFdICogbVszICogMSAtIDFdICsgcmlnaHQubVs0ICogNCAtIDFdICogbVs0ICogMSAtIDFdLAoJCQkJcmlnaHQubVs0ICogMSAtIDFdICogbVsxICogMiAtIDFdICsgcmlnaHQubVs0ICogMiAtIDFdICogbVsyICogMiAtIDFdICsgcmlnaHQubVs0ICogMyAtIDFdICogbVszICogMiAtIDFdICsgcmlnaHQubVs0ICogNCAtIDFdICogbVs0ICogMiAtIDFdLAoJCQkJcmlnaHQubVs0ICogMSAtIDFdICogbVsxICogMyAtIDFdICsgcmlnaHQubVs0ICogMiAtIDFdICogbVsyICogMyAtIDFdICsgcmlnaHQubVs0ICogMyAtIDFdICogbVszICogMyAtIDFdICsgcmlnaHQubVs0ICogNCAtIDFdICogbVs0ICogMyAtIDFdLAoJCQkJcmlnaHQubVs0ICogMSAtIDFdICogbVsxICogNCAtIDFdICsgcmlnaHQubVs0ICogMiAtIDFdICogbVsyICogNCAtIDFdICsgcmlnaHQubVs0ICogMyAtIDFdICogbVszICogNCAtIDFdICsgcmlnaHQubVs0ICogNCAtIDFdICogbVs0ICogNCAtIDFdCgkJCX07CgoJCQltZW1jcHkobSwgb3V0LCBzaXplb2YoVCkgKiAxNik7CgoJCQlyZXR1cm4gKnRoaXM7CgkJfQoKCQlib29sIG9wZXJhdG9yPT0gKCBjb25zdCBSTWF0cml4NDxUPiYgcmlnaHQgKSB7CgkJCXJldHVybiBtWzBdID09IHJpZ2h0Lm1bMF0gJiYKCQkJCW1bMV0gPT0gcmlnaHQubVsxXSAmJgoJCQkJbVsyXSA9PSByaWdodC5tWzJdICYmCgkJCQltWzNdID09IHJpZ2h0Lm1bM10gJiYKCQkJCW1bNF0gPT0gcmlnaHQubVs0XSAmJgoJCQkJbVs1XSA9PSByaWdodC5tWzVdICYmCgkJCQltWzZdID09IHJpZ2h0Lm1bNl0gJiYKCQkJCW1bN10gPT0gcmlnaHQubVs3XSAmJgoJCQkJbVs4XSA9PSByaWdodC5tWzhdICYmCgkJCQltWzldID09IHJpZ2h0Lm1bOV0gJiYKCQkJCW1bMTBdID09IHJpZ2h0Lm1bMTBdICYmCgkJCQltWzExXSA9PSByaWdodC5tWzExXSAmJgoJCQkJbVsxMl0gPT0gcmlnaHQubVsxMl0gJiYKCQkJCW1bMTNdID09IHJpZ2h0Lm1bMTNdICYmCgkJCQltWzE0XSA9PSByaWdodC5tWzE0XSAmJgoJCQkJbVsxNV0gPT0gcmlnaHQubVsxNV07CgkJfQoKCQlib29sIG9wZXJhdG9yIT0gKCBjb25zdCBSTWF0cml4NDxUPiYgcmlnaHQgKSB7CgkJCXJldHVybiAhKCp0aGlzID09IHJpZ2h0KTsKCQl9CgoJCWJvb2wgb3BlcmF0b3I9PSAoIFQqIHJpZ2h0ICkgewoJCQlyZXR1cm4gbVswXSA9PSByaWdodFswXSAmJgoJCQkJbVsxXSA9PSByaWdodFsxXSAmJgoJCQkJbVsyXSA9PSByaWdodFsyXSAmJgoJCQkJbVszXSA9PSByaWdodFszXSAmJgoJCQkJbVs0XSA9PSByaWdodFs0XSAmJgoJCQkJbVs1XSA9PSByaWdodFs1XSAmJgoJCQkJbVs2XSA9PSByaWdodFs2XSAmJgoJCQkJbVs3XSA9PSByaWdodFs3XSAmJgoJCQkJbVs4XSA9PSByaWdodFs4XSAmJgoJCQkJbVs5XSA9PSByaWdodFs5XSAmJgoJCQkJbVsxMF0gPT0gcmlnaHRbMTBdICYmCgkJCQltWzExXSA9PSByaWdodFsxMV0gJiYKCQkJCW1bMTJdID09IHJpZ2h0WzEyXSAmJgoJCQkJbVsxM10gPT0gcmlnaHRbMTNdICYmCgkJCQltWzE0XSA9PSByaWdodFsxNF0gJiYKCQkJCW1bMTVdID09IHJpZ2h0WzE1XTsKCQl9CgoJCWJvb2wgb3BlcmF0b3IhPSAoIFQqIHJpZ2h0ICkgewoJCQlyZXR1cm4gISgqdGhpcyA9PSByaWdodCk7CgkJfQoKCQlib29sIEVxdWFscyAoY29uc3QgUk1hdHJpeDQ8VD4mIHJpZ2h0KSB7CgkJCXJldHVybiBtWzBdID09IHJpZ2h0Lm1bMF0gJiYKCQkJCW1bMV0gPT0gcmlnaHQubVsxXSAmJgoJCQkJbVsyXSA9PSByaWdodC5tWzJdICYmCgkJCQltWzNdID09IHJpZ2h0Lm1bM10gJiYKCQkJCW1bNF0gPT0gcmlnaHQubVs0XSAmJgoJCQkJbVs1XSA9PSByaWdodC5tWzVdICYmCgkJCQltWzZdID09IHJpZ2h0Lm1bNl0gJiYKCQkJCW1bN10gPT0gcmlnaHQubVs3XSAmJgoJCQkJbVs4XSA9PSByaWdodC5tWzhdICYmCgkJCQltWzldID09IHJpZ2h0Lm1bOV0gJiYKCQkJCW1bMTBdID09IHJpZ2h0Lm1bMTBdICYmCgkJCQltWzExXSA9PSByaWdodC5tWzExXSAmJgoJCQkJbVsxMl0gPT0gcmlnaHQubVsxMl0gJiYKCQkJCW1bMTNdID09IHJpZ2h0Lm1bMTNdICYmCgkJCQltWzE0XSA9PSByaWdodC5tWzE0XSAmJgoJCQkJbVsxNV0gPT0gcmlnaHQubVsxNV07CgkJfQoKCQlUVmVjdG9yNDxUPiBvcGVyYXRvciogKCBjb25zdCBUVmVjdG9yNDxUPiYgcmlnaHQgKSBjb25zdCB7CgkJCXJldHVybiBUVmVjdG9yNDxUPiAoCgkJCQltMTEgKiByaWdodC54ICsKCQkJCW0xMiAqIHJpZ2h0LnkgKwoJCQkJbTEzICogcmlnaHQueiArCgkJCQltMTQgKiByaWdodC53LAoKCQkJCW0yMSAqIHJpZ2h0LnggKwoJCQkJbTIyICogcmlnaHQueSArCgkJCQltMjMgKiByaWdodC56ICsKCQkJCW0yNCAqIHJpZ2h0LncsCgoJCQkJbTMxICogcmlnaHQueCArCgkJCQltMzIgKiByaWdodC55ICsKCQkJCW0zMyAqIHJpZ2h0LnogKwoJCQkJbTM0ICogcmlnaHQudywKCgkJCQltNDEgKiByaWdodC54ICsKCQkJCW00MiAqIHJpZ2h0LnkgKwoJCQkJbTQzICogcmlnaHQueiArCgkJCQltNDQgKiByaWdodC53CgkJCQkpOwoJCX0KCgkJVFZlY3RvcjM8VD4gb3BlcmF0b3IqICggY29uc3QgVFZlY3RvcjM8VD4mIHJpZ2h0ICkgY29uc3QgewoJCQlyZXR1cm4gVFZlY3RvcjM8VD4gKAoJCQkJbTExICogcmlnaHQueCArCgkJCQltMTIgKiByaWdodC55ICsKCQkJCW0xMyAqIHJpZ2h0LnogKwoJCQkJbTE0LAoKCQkJCW0yMSAqIHJpZ2h0LnggKwoJCQkJbTIyICogcmlnaHQueSArCgkJCQltMjMgKiByaWdodC56ICsKCQkJCW0yNCwKCgkJCQltMzEgKiByaWdodC54ICsKCQkJCW0zMiAqIHJpZ2h0LnkgKwoJCQkJbTMzICogcmlnaHQueiArCgkJCQltMzQsCgoJCQkJbTQxICogcmlnaHQueCArCgkJCQltNDIgKiByaWdodC55ICsKCQkJCW00MyAqIHJpZ2h0LnogKwoJCQkJbTQ0CgkJCQkpOwoJCX0KCgkJUk1hdHJpeDQ8VD4gb3BlcmF0b3IqICggY29uc3QgUk1hdHJpeDQ8VD4mIHJpZ2h0ICkgY29uc3QgewoJCQlSTWF0cml4NDxUPiByID0geyBtWzBdICogcmlnaHQubVswXSArCgkJCQltWzFdICogcmlnaHQubVs0XSArCgkJCQltWzJdICogcmlnaHQubVs4XSArCgkJCQltWzNdICogcmlnaHQubVsxMl0sCgoJCQkJbVswXSAqIHJpZ2h0Lm1bMV0gKwoJCQkJbVsxXSAqIHJpZ2h0Lm1bNV0gKwoJCQkJbVsyXSAqIHJpZ2h0Lm1bOV0gKwoJCQkJbVszXSAqIHJpZ2h0Lm1bMTNdLAoKCQkJCW1bMF0gKiByaWdodC5tWzJdICsKCQkJCW1bMV0gKiByaWdodC5tWzZdICsKCQkJCW1bMl0gKiByaWdodC5tWzEwXSArCgkJCQltWzNdICogcmlnaHQubVsxNF0sCgoJCQkJbVswXSAqIHJpZ2h0Lm1bM10gKwoJCQkJbVsxXSAqIHJpZ2h0Lm1bN10gKwoJCQkJbVsyXSAqIHJpZ2h0Lm1bMTFdICsKCQkJCW1bM10gKiByaWdodC5tWzE1XSwKCgkJCQltWzRdICogcmlnaHQubVswXSArCgkJCQltWzVdICogcmlnaHQubVs0XSArCgkJCQltWzZdICogcmlnaHQubVs4XSArCgkJCQltWzddICogcmlnaHQubVsxMl0sCgoJCQkJbVs0XSAqIHJpZ2h0Lm1bMV0gKwoJCQkJbVs1XSAqIHJpZ2h0Lm1bNV0gKwoJCQkJbVs2XSAqIHJpZ2h0Lm1bOV0gKwoJCQkJbVs3XSAqIHJpZ2h0Lm1bMTNdLAoKCQkJCW1bNF0gKiByaWdodC5tWzJdICsKCQkJCW1bNV0gKiByaWdodC5tWzZdICsKCQkJCW1bNl0gKiByaWdodC5tWzEwXSArCgkJCQltWzddICogcmlnaHQubVsxNF0sCgoJCQkJbVs0XSAqIHJpZ2h0Lm1bM10gKwoJCQkJbVs1XSAqIHJpZ2h0Lm1bN10gKwoJCQkJbVs2XSAqIHJpZ2h0Lm1bMTFdICsKCQkJCW1bN10gKiByaWdodC5tWzE1XSwKCgkJCQltWzhdICogcmlnaHQubVswXSArCgkJCQltWzldICogcmlnaHQubVs0XSArCgkJCQltWzEwXSAqIHJpZ2h0Lm1bOF0gKwoJCQkJbVsxMV0gKiByaWdodC5tWzEyXSwKCgkJCQltWzhdICogcmlnaHQubVsxXSArCgkJCQltWzldICogcmlnaHQubVs1XSArCgkJCQltWzEwXSAqIHJpZ2h0Lm1bOV0gKwoJCQkJbVsxMV0gKiByaWdodC5tWzEzXSwKCgkJCQltWzhdICogcmlnaHQubVsyXSArCgkJCQltWzldICogcmlnaHQubVs2XSArCgkJCQltWzEwXSAqIHJpZ2h0Lm1bMTBdICsKCQkJCW1bMTFdICogcmlnaHQubVsxNF0sCgoJCQkJbVs4XSAqIHJpZ2h0Lm1bM10gKwoJCQkJbVs5XSAqIHJpZ2h0Lm1bN10gKwoJCQkJbVsxMF0gKiByaWdodC5tWzExXSArCgkJCQltWzExXSAqIHJpZ2h0Lm1bMTVdLAoKCQkJCW1bMTJdICogcmlnaHQubVswXSArCgkJCQltWzEzXSAqIHJpZ2h0Lm1bNF0gKwoJCQkJbVsxNF0gKiByaWdodC5tWzhdICsKCQkJCW1bMTVdICogcmlnaHQubVsxMl0sCgoJCQkJbVsxMl0gKiByaWdodC5tWzFdICsKCQkJCW1bMTNdICogcmlnaHQubVs1XSArCgkJCQltWzE0XSAqIHJpZ2h0Lm1bOV0gKwoJCQkJbVsxNV0gKiByaWdodC5tWzEzXSwKCgkJCQltWzEyXSAqIHJpZ2h0Lm1bMl0gKwoJCQkJbVsxM10gKiByaWdodC5tWzZdICsKCQkJCW1bMTRdICogcmlnaHQubVsxMF0gKwoJCQkJbVsxNV0gKiByaWdodC5tWzE0XSwKCgkJCQltWzEyXSAqIHJpZ2h0Lm1bM10gKwoJCQkJbVsxM10gKiByaWdodC5tWzddICsKCQkJCW1bMTRdICogcmlnaHQubVsxMV0gKwoJCQkJbVsxNV0gKiByaWdodC5tWzE1XQoJCQl9OwoJCQlyZXR1cm4gcjsKCQl9CgoJCWJvb2wgb3BlcmF0b3I9PSAoIGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCApIGNvbnN0IHsKCQkJcmV0dXJuIG1lbWNtcChtLCByaWdodC5tLCBzaXplb2YoVCkgKiAxNikgPT0gMDsKCQl9CgoJCWJvb2wgb3BlcmF0b3IhPSAoIGNvbnN0IFJNYXRyaXg0PFQ+JiByaWdodCApIGNvbnN0IHsKCQkJcmV0dXJuIG1lbWNtcChtLCByaWdodC5tLCBzaXplb2YoVCkgKiAxNikgIT0gMDsKCQl9CgoJCWJvb2wgb3BlcmF0b3I9PSAoIFQqIHJpZ2h0ICkgY29uc3QgewoJCQlyZXR1cm4gbWVtY21wKG0sIHJpZ2h0LCBzaXplb2YoVCkgKiAxNikgPT0gMDsKCQl9CgoJCWJvb2wgb3BlcmF0b3IhPSAoIFQqIHJpZ2h0ICkgY29uc3QgewoJCQlyZXR1cm4gbWVtY21wKG0sIHJpZ2h0LCBzaXplb2YoVCkgKiAxNikgIT0gMDsKCQl9CgoJCW9wZXJhdG9yIFQqICgpIGNvbnN0IHsKCQkJcmV0dXJuIChUKiltOwoJCX0KCgkJVCYgb3BlcmF0b3JbXSAoaW50IGluZGV4KSB7CgkJCXJldHVybiBtW2luZGV4XTsKCQl9CgoJCVQmIG9wZXJhdG9yKCkgKGludCBjb2x1bW4sIGludCByb3cpIHsKCQkJcmV0dXJuIG1bcm93ICogNCArIGNvbHVtbl07CgkJfQoKCQlzdGF0aWMgVFZlY3RvcjM8VD4gVHJhbnNmb3JtIChjb25zdCBSTWF0cml4NDxUPiYgbWF0cml4LCBjb25zdCBUVmVjdG9yMzxUPiYgc291cmNlKSB7CgkJCXJldHVybiBtYXRyaXggKiBzb3VyY2U7CgkJfQoKCQlzdGF0aWMgVFZlY3RvcjQ8VD4gVHJhbnNmb3JtIChjb25zdCBSTWF0cml4NDxUPiYgbWF0cml4LCBjb25zdCBUVmVjdG9yNDxUPiYgc291cmNlKSB7CgkJCXJldHVybiBtYXRyaXggKiBzb3VyY2U7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gVHJhbnNwb3NlIChjb25zdCBSTWF0cml4NDxUPiYgbWF0cml4KSB7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQltYXRyaXgubVswXSwKCQkJCW1hdHJpeC5tWzRdLAoJCQkJbWF0cml4Lm1bOF0sCgkJCQltYXRyaXgubVsxMl0sCgkJCQltYXRyaXgubVsxXSwKCQkJCW1hdHJpeC5tWzVdLAoJCQkJbWF0cml4Lm1bOV0sCgkJCQltYXRyaXgubVsxM10sCgkJCQltYXRyaXgubVsyXSwKCQkJCW1hdHJpeC5tWzZdLAoJCQkJbWF0cml4Lm1bMTBdLAoJCQkJbWF0cml4Lm1bMTRdLAoJCQkJbWF0cml4Lm1bM10sCgkJCQltYXRyaXgubVs3XSwKCQkJCW1hdHJpeC5tWzExXSwKCQkJCW1hdHJpeC5tWzE1XQoJCQl9OwoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBBZGpvaW50IChjb25zdCBSTWF0cml4NDxUPiYgbWF0cml4KSB7CgkJCVQgYTAgPSBtYXRyaXgubVswXSAqIG1hdHJpeC5tWzVdIC0gbWF0cml4Lm1bMV0gKiBtYXRyaXgubVs0XTsKCQkJVCBhMSA9IG1hdHJpeC5tWzBdICogbWF0cml4Lm1bNl0gLSBtYXRyaXgubVsyXSAqIG1hdHJpeC5tWzRdOwoJCQlUIGEyID0gbWF0cml4Lm1bMF0gKiBtYXRyaXgubVs3XSAtIG1hdHJpeC5tWzNdICogbWF0cml4Lm1bNF07CgkJCVQgYTMgPSBtYXRyaXgubVsxXSAqIG1hdHJpeC5tWzZdIC0gbWF0cml4Lm1bMl0gKiBtYXRyaXgubVs1XTsKCQkJVCBhNCA9IG1hdHJpeC5tWzFdICogbWF0cml4Lm1bN10gLSBtYXRyaXgubVszXSAqIG1hdHJpeC5tWzVdOwoJCQlUIGE1ID0gbWF0cml4Lm1bMl0gKiBtYXRyaXgubVs3XSAtIG1hdHJpeC5tWzNdICogbWF0cml4Lm1bNl07CgkJCVQgYjAgPSBtYXRyaXgubVs4XSAqIG1hdHJpeC5tWzEzXSAtIG1hdHJpeC5tWzldICogbWF0cml4Lm1bMTJdOwoJCQlUIGIxID0gbWF0cml4Lm1bOF0gKiBtYXRyaXgubVsxNF0gLSBtYXRyaXgubVsxMF0gKiBtYXRyaXgubVsxMl07CgkJCVQgYjIgPSBtYXRyaXgubVs4XSAqIG1hdHJpeC5tWzE1XSAtIG1hdHJpeC5tWzExXSAqIG1hdHJpeC5tWzEyXTsKCQkJVCBiMyA9IG1hdHJpeC5tWzldICogbWF0cml4Lm1bMTRdIC0gbWF0cml4Lm1bMTBdICogbWF0cml4Lm1bMTNdOwoJCQlUIGI0ID0gbWF0cml4Lm1bOV0gKiBtYXRyaXgubVsxNV0gLSBtYXRyaXgubVsxMV0gKiBtYXRyaXgubVsxM107CgkJCVQgYjUgPSBtYXRyaXgubVsxMF0gKiBtYXRyaXgubVsxNV0gLSBtYXRyaXgubVsxMV0gKiBtYXRyaXgubVsxNF07CgoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJKyBtYXRyaXgubVs1XSAqIGI1IC0gbWF0cml4Lm1bNl0gKiBiNCArIG1hdHJpeC5tWzddICogYjMsCgkJCQktIG1hdHJpeC5tWzFdICogYjUgKyBtYXRyaXgubVsyXSAqIGI0IC0gbWF0cml4Lm1bM10gKiBiMywKCQkJCSsgbWF0cml4Lm1bMTNdICogYTUgLSBtYXRyaXgubVsxNF0gKiBhNCArIG1hdHJpeC5tWzE1XSAqIGEzLAoJCQkJLSBtYXRyaXgubVs5XSAqIGE1ICsgbWF0cml4Lm1bMTBdICogYTQgLSBtYXRyaXgubVsxMV0gKiBhMywKCQkJCS0gbWF0cml4Lm1bNF0gKiBiNSArIG1hdHJpeC5tWzZdICogYjIgLSBtYXRyaXgubVs3XSAqIGIxLAoJCQkJKyBtYXRyaXgubVswXSAqIGI1IC0gbWF0cml4Lm1bMl0gKiBiMiArIG1hdHJpeC5tWzNdICogYjEsCgkJCQktIG1hdHJpeC5tWzEyXSAqIGE1ICsgbWF0cml4Lm1bMTRdICogYTIgLSBtYXRyaXgubVsxNV0gKiBhMSwKCQkJCSsgbWF0cml4Lm1bOF0gKiBhNSAtIG1hdHJpeC5tWzEwXSAqIGEyICsgbWF0cml4Lm1bMTFdICogYTEsCgkJCQkrIG1hdHJpeC5tWzRdICogYjQgLSBtYXRyaXgubVs1XSAqIGIyICsgbWF0cml4Lm1bN10gKiBiMCwKCQkJCS0gbWF0cml4Lm1bMF0gKiBiNCArIG1hdHJpeC5tWzFdICogYjIgLSBtYXRyaXgubVszXSAqIGIwLAoJCQkJKyBtYXRyaXgubVsxMl0gKiBhNCAtIG1hdHJpeC5tWzEzXSAqIGEyICsgbWF0cml4Lm1bMTVdICogYTAsCgkJCQktIG1hdHJpeC5tWzhdICogYTQgKyBtYXRyaXgubVs5XSAqIGEyIC0gbWF0cml4Lm1bMTFdICogYTAsCgkJCQktIG1hdHJpeC5tWzRdICogYjMgKyBtYXRyaXgubVs1XSAqIGIxIC0gbWF0cml4Lm1bNl0gKiBiMCwKCQkJCSsgbWF0cml4Lm1bMF0gKiBiMyAtIG1hdHJpeC5tWzFdICogYjEgKyBtYXRyaXgubVsyXSAqIGIwLAoJCQkJLSBtYXRyaXgubVsxMl0gKiBhMyArIG1hdHJpeC5tWzEzXSAqIGExIC0gbWF0cml4Lm1bMTRdICogYTAsCgkJCQkrIG1hdHJpeC5tWzhdICogYTMgLSBtYXRyaXgubVs5XSAqIGExICsgbWF0cml4Lm1bMTBdICogYTAKCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gSW52ZXJzZSAoY29uc3QgUk1hdHJpeDQ8VD4mIG1hdHJpeCkgewoJCQlUIGEwID0gbWF0cml4Lm1bMF0gKiBtYXRyaXgubVs1XSAtIG1hdHJpeC5tWzFdICogbWF0cml4Lm1bNF07CgkJCVQgYTEgPSBtYXRyaXgubVswXSAqIG1hdHJpeC5tWzZdIC0gbWF0cml4Lm1bMl0gKiBtYXRyaXgubVs0XTsKCQkJVCBhMiA9IG1hdHJpeC5tWzBdICogbWF0cml4Lm1bN10gLSBtYXRyaXgubVszXSAqIG1hdHJpeC5tWzRdOwoJCQlUIGEzID0gbWF0cml4Lm1bMV0gKiBtYXRyaXgubVs2XSAtIG1hdHJpeC5tWzJdICogbWF0cml4Lm1bNV07CgkJCVQgYTQgPSBtYXRyaXgubVsxXSAqIG1hdHJpeC5tWzddIC0gbWF0cml4Lm1bM10gKiBtYXRyaXgubVs1XTsKCQkJVCBhNSA9IG1hdHJpeC5tWzJdICogbWF0cml4Lm1bN10gLSBtYXRyaXgubVszXSAqIG1hdHJpeC5tWzZdOwoJCQlUIGIwID0gbWF0cml4Lm1bOF0gKiBtYXRyaXgubVsxM10gLSBtYXRyaXgubVs5XSAqIG1hdHJpeC5tWzEyXTsKCQkJVCBiMSA9IG1hdHJpeC5tWzhdICogbWF0cml4Lm1bMTRdIC0gbWF0cml4Lm1bMTBdICogbWF0cml4Lm1bMTJdOwoJCQlUIGIyID0gbWF0cml4Lm1bOF0gKiBtYXRyaXgubVsxNV0gLSBtYXRyaXgubVsxMV0gKiBtYXRyaXgubVsxMl07CgkJCVQgYjMgPSBtYXRyaXgubVs5XSAqIG1hdHJpeC5tWzE0XSAtIG1hdHJpeC5tWzEwXSAqIG1hdHJpeC5tWzEzXTsKCQkJVCBiNCA9IG1hdHJpeC5tWzldICogbWF0cml4Lm1bMTVdIC0gbWF0cml4Lm1bMTFdICogbWF0cml4Lm1bMTNdOwoJCQlUIGI1ID0gbWF0cml4Lm1bMTBdICogbWF0cml4Lm1bMTVdIC0gbWF0cml4Lm1bMTFdICogbWF0cml4Lm1bMTRdOwoKCQkJVCBkZXQgPSBhMCAqIGI1IC0gYTEgKiBiNCArIGEyICogYjMgKyBhMyAqIGIyIC0gYTQgKiBiMSArIGE1ICogYjA7CgkJCVJNYXRyaXg0PFQ+IGludmVyc2UgPSB7IDAgfTsKCQkJaWYgKE1hdGhlbWE8VD46OkFicyhkZXQpID4gVCgwKSkgewoJCQkJaW52ZXJzZS5tWzBdID0gKyBtYXRyaXgubVs1XSAqIGI1IC0gbWF0cml4Lm1bNl0gKiBiNCArIG1hdHJpeC5tWzddICogYjM7CgkJCQlpbnZlcnNlLm1bNF0gPSAtIG1hdHJpeC5tWzRdICogYjUgKyBtYXRyaXgubVs2XSAqIGIyIC0gbWF0cml4Lm1bN10gKiBiMTsKCQkJCWludmVyc2UubVs4XSA9ICsgbWF0cml4Lm1bNF0gKiBiNCAtIG1hdHJpeC5tWzVdICogYjIgKyBtYXRyaXgubVs3XSAqIGIwOwoJCQkJaW52ZXJzZS5tWzEyXSA9IC0gbWF0cml4Lm1bNF0gKiBiMyArIG1hdHJpeC5tWzVdICogYjEgLSBtYXRyaXgubVs2XSAqIGIwOwoJCQkJaW52ZXJzZS5tWzFdID0gLSBtYXRyaXgubVsxXSAqIGI1ICsgbWF0cml4Lm1bMl0gKiBiNCAtIG1hdHJpeC5tWzNdICogYjM7CgkJCQlpbnZlcnNlLm1bNV0gPSArIG1hdHJpeC5tWzBdICogYjUgLSBtYXRyaXgubVsyXSAqIGIyICsgbWF0cml4Lm1bM10gKiBiMTsKCQkJCWludmVyc2UubVs5XSA9IC0gbWF0cml4Lm1bMF0gKiBiNCArIG1hdHJpeC5tWzFdICogYjIgLSBtYXRyaXgubVszXSAqIGIwOwoJCQkJaW52ZXJzZS5tWzEzXSA9ICsgbWF0cml4Lm1bMF0gKiBiMyAtIG1hdHJpeC5tWzFdICogYjEgKyBtYXRyaXgubVsyXSAqIGIwOwoJCQkJaW52ZXJzZS5tWzJdID0gKyBtYXRyaXgubVsxM10gKiBhNSAtIG1hdHJpeC5tWzE0XSAqIGE0ICsgbWF0cml4Lm1bMTVdICogYTM7CgkJCQlpbnZlcnNlLm1bNl0gPSAtIG1hdHJpeC5tWzEyXSAqIGE1ICsgbWF0cml4Lm1bMTRdICogYTIgLSBtYXRyaXgubVsxNV0gKiBhMTsKCQkJCWludmVyc2UubVsxMF0gPSArIG1hdHJpeC5tWzEyXSAqIGE0IC0gbWF0cml4Lm1bMTNdICogYTIgKyBtYXRyaXgubVsxNV0gKiBhMDsKCQkJCWludmVyc2UubVsxNF0gPSAtIG1hdHJpeC5tWzEyXSAqIGEzICsgbWF0cml4Lm1bMTNdICogYTEgLSBtYXRyaXgubVsxNF0gKiBhMDsKCQkJCWludmVyc2UubVszXSA9IC0gbWF0cml4Lm1bOV0gKiBhNSArIG1hdHJpeC5tWzEwXSAqIGE0IC0gbWF0cml4Lm1bMTFdICogYTM7CgkJCQlpbnZlcnNlLm1bN10gPSArIG1hdHJpeC5tWzhdICogYTUgLSBtYXRyaXgubVsxMF0gKiBhMiArIG1hdHJpeC5tWzExXSAqIGExOwoJCQkJaW52ZXJzZS5tWzExXSA9IC0gbWF0cml4Lm1bOF0gKiBhNCArIG1hdHJpeC5tWzldICogYTIgLSBtYXRyaXgubVsxMV0gKiBhMDsKCQkJCWludmVyc2UubVsxNV0gPSArIG1hdHJpeC5tWzhdICogYTMgLSBtYXRyaXgubVs5XSAqIGExICsgbWF0cml4Lm1bMTBdICogYTA7CgoJCQkJVCBpbnZEZXQgPSAoVCgxKSkgLyBkZXQ7CgkJCQlpbnZlcnNlLm1bMF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxXSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzJdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bM10gICo9IGludkRldDsKCQkJCWludmVyc2UubVs0XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzVdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bNl0gICo9IGludkRldDsKCQkJCWludmVyc2UubVs3XSAgKj0gaW52RGV0OwoJCQkJaW52ZXJzZS5tWzhdICAqPSBpbnZEZXQ7CgkJCQlpbnZlcnNlLm1bOV0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMV0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxMl0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxM10gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxNF0gICo9IGludkRldDsKCQkJCWludmVyc2UubVsxNV0gICo9IGludkRldDsKCgkJCX0KCgkJCXJldHVybiBpbnZlcnNlOwoJCX0KCgkJc3RhdGljIGJvb2wgSW52ZXJ0IChjb25zdCBSTWF0cml4NDxUPiYgbWF0cml4LCBSTWF0cml4NDxUPiYgb3V0KSB7CgkJCVQgYTAgPSBtYXRyaXgubVswXSAqIG1hdHJpeC5tWzVdIC0gbWF0cml4Lm1bMV0gKiBtYXRyaXgubVs0XTsKCQkJVCBhMSA9IG1hdHJpeC5tWzBdICogbWF0cml4Lm1bNl0gLSBtYXRyaXgubVsyXSAqIG1hdHJpeC5tWzRdOwoJCQlUIGEyID0gbWF0cml4Lm1bMF0gKiBtYXRyaXgubVs3XSAtIG1hdHJpeC5tWzNdICogbWF0cml4Lm1bNF07CgkJCVQgYTMgPSBtYXRyaXgubVsxXSAqIG1hdHJpeC5tWzZdIC0gbWF0cml4Lm1bMl0gKiBtYXRyaXgubVs1XTsKCQkJVCBhNCA9IG1hdHJpeC5tWzFdICogbWF0cml4Lm1bN10gLSBtYXRyaXgubVszXSAqIG1hdHJpeC5tWzVdOwoJCQlUIGE1ID0gbWF0cml4Lm1bMl0gKiBtYXRyaXgubVs3XSAtIG1hdHJpeC5tWzNdICogbWF0cml4Lm1bNl07CgkJCVQgYjAgPSBtYXRyaXgubVs4XSAqIG1hdHJpeC5tWzEzXSAtIG1hdHJpeC5tWzldICogbWF0cml4Lm1bMTJdOwoJCQlUIGIxID0gbWF0cml4Lm1bOF0gKiBtYXRyaXgubVsxNF0gLSBtYXRyaXgubVsxMF0gKiBtYXRyaXgubVsxMl07CgkJCVQgYjIgPSBtYXRyaXgubVs4XSAqIG1hdHJpeC5tWzE1XSAtIG1hdHJpeC5tWzExXSAqIG1hdHJpeC5tWzEyXTsKCQkJVCBiMyA9IG1hdHJpeC5tWzldICogbWF0cml4Lm1bMTRdIC0gbWF0cml4Lm1bMTBdICogbWF0cml4Lm1bMTNdOwoJCQlUIGI0ID0gbWF0cml4Lm1bOV0gKiBtYXRyaXgubVsxNV0gLSBtYXRyaXgubVsxMV0gKiBtYXRyaXgubVsxM107CgkJCVQgYjUgPSBtYXRyaXgubVsxMF0gKiBtYXRyaXgubVsxNV0gLSBtYXRyaXgubVsxMV0gKiBtYXRyaXgubVsxNF07CgoJCQlUIGRldCA9IGEwICogYjUgLSBhMSAqIGI0ICsgYTIgKiBiMyArIGEzICogYjIgLSBhNCAqIGIxICsgYTUgKiBiMDsKCQkJaWYgKE1hdGhlbWE8VD46OkFicyhkZXQpID4gVCgwKSkgewoJCQkJb3V0Lm1bMF0gPSArIG1hdHJpeC5tWzVdICogYjUgLSBtYXRyaXgubVs2XSAqIGI0ICsgbWF0cml4Lm1bN10gKiBiMzsKCQkJCW91dC5tWzRdID0gLSBtYXRyaXgubVs0XSAqIGI1ICsgbWF0cml4Lm1bNl0gKiBiMiAtIG1hdHJpeC5tWzddICogYjE7CgkJCQlvdXQubVs4XSA9ICsgbWF0cml4Lm1bNF0gKiBiNCAtIG1hdHJpeC5tWzVdICogYjIgKyBtYXRyaXgubVs3XSAqIGIwOwoJCQkJb3V0Lm1bMTJdID0gLSBtYXRyaXgubVs0XSAqIGIzICsgbWF0cml4Lm1bNV0gKiBiMSAtIG1hdHJpeC5tWzZdICogYjA7CgkJCQlvdXQubVsxXSA9IC0gbWF0cml4Lm1bMV0gKiBiNSArIG1hdHJpeC5tWzJdICogYjQgLSBtYXRyaXgubVszXSAqIGIzOwoJCQkJb3V0Lm1bNV0gPSArIG1hdHJpeC5tWzBdICogYjUgLSBtYXRyaXgubVsyXSAqIGIyICsgbWF0cml4Lm1bM10gKiBiMTsKCQkJCW91dC5tWzldID0gLSBtYXRyaXgubVswXSAqIGI0ICsgbWF0cml4Lm1bMV0gKiBiMiAtIG1hdHJpeC5tWzNdICogYjA7CgkJCQlvdXQubVsxM10gPSArIG1hdHJpeC5tWzBdICogYjMgLSBtYXRyaXgubVsxXSAqIGIxICsgbWF0cml4Lm1bMl0gKiBiMDsKCQkJCW91dC5tWzJdID0gKyBtYXRyaXgubVsxM10gKiBhNSAtIG1hdHJpeC5tWzE0XSAqIGE0ICsgbWF0cml4Lm1bMTVdICogYTM7CgkJCQlvdXQubVs2XSA9IC0gbWF0cml4Lm1bMTJdICogYTUgKyBtYXRyaXgubVsxNF0gKiBhMiAtIG1hdHJpeC5tWzE1XSAqIGExOwoJCQkJb3V0Lm1bMTBdID0gKyBtYXRyaXgubVsxMl0gKiBhNCAtIG1hdHJpeC5tWzEzXSAqIGEyICsgbWF0cml4Lm1bMTVdICogYTA7CgkJCQlvdXQubVsxNF0gPSAtIG1hdHJpeC5tWzEyXSAqIGEzICsgbWF0cml4Lm1bMTNdICogYTEgLSBtYXRyaXgubVsxNF0gKiBhMDsKCQkJCW91dC5tWzNdID0gLSBtYXRyaXgubVs5XSAqIGE1ICsgbWF0cml4Lm1bMTBdICogYTQgLSBtYXRyaXgubVsxMV0gKiBhMzsKCQkJCW91dC5tWzddID0gKyBtYXRyaXgubVs4XSAqIGE1IC0gbWF0cml4Lm1bMTBdICogYTIgKyBtYXRyaXgubVsxMV0gKiBhMTsKCQkJCW91dC5tWzExXSA9IC0gbWF0cml4Lm1bOF0gKiBhNCArIG1hdHJpeC5tWzldICogYTIgLSBtYXRyaXgubVsxMV0gKiBhMDsKCQkJCW91dC5tWzE1XSA9ICsgbWF0cml4Lm1bOF0gKiBhMyAtIG1hdHJpeC5tWzldICogYTEgKyBtYXRyaXgubVsxMF0gKiBhMDsKCgkJCQlUIGludkRldCA9IChUKDEpKSAvIGRldDsKCQkJCW91dC5tWzBdICAqPSBpbnZEZXQ7CgkJCQlvdXQubVsxXSAgKj0gaW52RGV0OwoJCQkJb3V0Lm1bMl0gICo9IGludkRldDsKCQkJCW91dC5tWzNdICAqPSBpbnZEZXQ7CgkJCQlvdXQubVs0XSAgKj0gaW52RGV0OwoJCQkJb3V0Lm1bNV0gICo9IGludkRldDsKCQkJCW91dC5tWzZdICAqPSBpbnZEZXQ7CgkJCQlvdXQubVs3XSAgKj0gaW52RGV0OwoJCQkJb3V0Lm1bOF0gICo9IGludkRldDsKCQkJCW91dC5tWzldICAqPSBpbnZEZXQ7CgkJCQlvdXQubVsxMF0gICo9IGludkRldDsKCQkJCW91dC5tWzExXSAgKj0gaW52RGV0OwoJCQkJb3V0Lm1bMTJdICAqPSBpbnZEZXQ7CgkJCQlvdXQubVsxM10gICo9IGludkRldDsKCQkJCW91dC5tWzE0XSAgKj0gaW52RGV0OwoJCQkJb3V0Lm1bMTVdICAqPSBpbnZEZXQ7CgoJCQkJcmV0dXJuIHRydWU7CgkJCX0KCgkJCXJldHVybiBmYWxzZTsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVUcmFuc2xhdGlvbiAoVCBkeCwgVCBkeSwgVCBkeikgewoJCQlSTWF0cml4NDxUPiByID0geyBUKDEpLCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgxKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMSksIFQoMCksCgkJCQlkeCwgZHksIGR6LCBUKDEpfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlVHJhbnNsYXRpb24gKGNvbnN0IFRWZWN0b3IzPFQ+JiB0cmFuc2xhdGlvbikgewoJCQlyZXR1cm4gQ3JlYXRlVHJhbnNsYXRpb24odHJhbnNsYXRpb24ueCwgdHJhbnNsYXRpb24ueSwgdHJhbnNsYXRpb24ueik7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUm90YXRpb25YIChUIHJhZGlhbnMpIHsKCQkJVCBjb3NhID0gTWF0aGVtYTxUPjo6Q29zKHJhZGlhbnMpOwoJCQlUIHNpbmEgPSBNYXRoZW1hPFQ+OjpTaW4ocmFkaWFucyk7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQlUKDEpLCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgY29zYSwgLXNpbmEsIFQoMCksCgkJCQlUKDApLCBzaW5hLCBjb3NhLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgwKSwgVCgxKX07CgkJCXJldHVybiByOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZVJvdGF0aW9uWSAoVCByYWRpYW5zKSB7CgkJCVQgY29zYSA9IE1hdGhlbWE8VD46OkNvcyhyYWRpYW5zKTsKCQkJVCBzaW5hID0gTWF0aGVtYTxUPjo6U2luKHJhZGlhbnMpOwoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJY29zYSwgVCgwKSwgc2luYSwgVCgwKSwKCQkJCVQoMCksIFQoMSksIFQoMCksIFQoMCksCgkJCQktc2luYSwgVCgwKSwgY29zYSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUm90YXRpb25aIChUIHJhZGlhbnMpIHsKCQkJVCBjb3NhID0gTWF0aGVtYTxUPjo6Q29zKHJhZGlhbnMpOwoJCQlUIHNpbmEgPSBNYXRoZW1hPFQ+OjpTaW4ocmFkaWFucyk7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQljb3NhLCAtc2luYSwgVCgwKSwgVCgwKSwKCQkJCXNpbmEsIGNvc2EsIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDApLCBUKDEpLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgwKSwgVCgxKSB9OwoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVSb3RhdGlvbiAoVCB4cmFkaWFucywgVCB5cmFkaWFucywgVCB6cmFkaWFucykgewoJCQlUIHhjb3MgPSBNYXRoZW1hPFQ+OjpDb3MoeHJhZGlhbnMpOwoJCQlUIHhzaW4gPSBNYXRoZW1hPFQ+OjpTaW4oeHJhZGlhbnMpOwoJCQlUIHpjb3MgPSBNYXRoZW1hPFQ+OjpDb3MoenJhZGlhbnMpOwoJCQlUIHpzaW4gPSBNYXRoZW1hPFQ+OjpTaW4oenJhZGlhbnMpOwoJCQlUIHljb3MgPSBNYXRoZW1hPFQ+OjpDb3MoeXJhZGlhbnMpOwoJCQlUIHlzaW4gPSBNYXRoZW1hPFQ+OjpTaW4oeXJhZGlhbnMpOwoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJeWNvcyAqIHpjb3MsIC14Y29zICogenNpbiArIHhzaW4gKiB5c2luICogemNvcywgeHNpbiAqIHpzaW4gKyB4Y29zICogeXNpbiAqIHpjb3MsIFQoMCksCgkJCQl5Y29zICogenNpbiwgeGNvcyAqIHpjb3MgKyB4c2luICogeXNpbiAqIHpzaW4sIC14c2luICogemNvcyArIHhjb3MgKiB5c2luICogenNpbiwgVCgwKSwKCQkJCXlzaW4sIHhzaW4gKiB5Y29zLCB4Y29zICogeWNvcywgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUm90YXRpb24gKGNvbnN0IFRWZWN0b3IzPFQ+JiB5YXdwaXRjaHJvbGwpIHsKCQkJcmV0dXJuIENyZWF0ZVJvdGF0aW9uKHlhd3BpdGNocm9sbC54LCB5YXdwaXRjaHJvbGwueSwgeWF3cGl0Y2hyb2xsLnopOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZVJvdGF0aW9uQXhpcyAoVFZlY3RvcjM8VD4gYXhpcywgVCByYWRpYW5zKSB7CgkJCWF4aXMuTm9ybWFsaXplKCk7CgkJCVQgY29zYSA9IE1hdGhlbWE8VD46OkNvcyhyYWRpYW5zKTsKCQkJVCBzaW5hID0gTWF0aGVtYTxUPjo6U2luKHJhZGlhbnMpOwoJCQlUIGFmZmNvc2EgPSBUKDEpIC0gY29zYTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCShheGlzLnggKiBheGlzLngpICogYWZmY29zYSArIGNvc2EsIChheGlzLnggKiBheGlzLnkpICogYWZmY29zYSAtIChheGlzLnogKiBzaW5hKSwgKGF4aXMueCAqIGF4aXMueikgKiBhZmZjb3NhICsgKGF4aXMueSAqIHNpbmEpLCBUKDApLAoJCQkJKGF4aXMueSAqIGF4aXMueCkgKiBhZmZjb3NhICsgKGF4aXMueiAqIHNpbmEpLCAoYXhpcy55ICogYXhpcy55KSAqIGFmZmNvc2EgKyBjb3NhLCAoYXhpcy55ICogYXhpcy56KSAqIGFmZmNvc2EgLSAoYXhpcy54ICogc2luYSksIFQoMCksCgkJCQkoYXhpcy56ICogYXhpcy54KSAqIGFmZmNvc2EgLSAoYXhpcy55ICogc2luYSksIChheGlzLnogKiBheGlzLnkpICogYWZmY29zYSArIChheGlzLnggKiBzaW5hKSwgKGF4aXMueiAqIGF4aXMueikgKiBhZmZjb3NhICsgY29zYSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUm90YXRpb25RdWF0ZXJuaW9uIChjb25zdCBUUXVhdGVybmlvbjxUPiYgcXVhdGVybmlvbikgewoJCQlUIHcyID0gY2FzdHRvKFQsIHF1YXRlcm5pb24udyAqIHF1YXRlcm5pb24udyk7CgkJCVQgeDIgPSBjYXN0dG8oVCwgcXVhdGVybmlvbi54ICogcXVhdGVybmlvbi54KTsKCQkJVCB5MiA9IGNhc3R0byhULCBxdWF0ZXJuaW9uLnkgKiBxdWF0ZXJuaW9uLnkpOwoJCQlUIHoyID0gY2FzdHRvKFQsIHF1YXRlcm5pb24ueiAqIHF1YXRlcm5pb24ueik7CgkJCVQgZHggPSBjYXN0dG8oVCwgMiAqIHF1YXRlcm5pb24ueCk7CgkJCVQgZHkgPSBjYXN0dG8oVCwgMiAqIHF1YXRlcm5pb24ueSk7CgkJCVQgZHcgPSBjYXN0dG8oVCwgMiAqIHF1YXRlcm5pb24udyk7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQl3MiArIHgyIC0geTIgLSB6MiwgZHggKiBxdWF0ZXJuaW9uLnkgLSBkdyAqIHF1YXRlcm5pb24ueiwgZHggKiBxdWF0ZXJuaW9uLnogKyBkdyAqIHF1YXRlcm5pb24ueSwgVCgwKSwKCQkJCWR4ICogcXVhdGVybmlvbi55ICsgZHcgKiBxdWF0ZXJuaW9uLnosIHcyIC0geDIgKyB5MiAtIHoyLCBkeSAqIHF1YXRlcm5pb24ueiArIGR3ICogcXVhdGVybmlvbi54LCBUKDApLAoJCQkJZHggKiBxdWF0ZXJuaW9uLnogLSBkdyAqIHF1YXRlcm5pb24ueSwgZHkgKiBxdWF0ZXJuaW9uLnogLSBkdyAqIHF1YXRlcm5pb24ueCwgdzIgLSB4MiAtIHkyICsgejIsIFQoMCksCgkJCQlUKDApLCBUKDApLCBUKDApLCBUKDEpIH07CgkJCXJldHVybiByOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZVNjYWxlIChUIHN4LCBUIHN5LCBUIHN6KSB7CgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQlzeCwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIHN5LCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgc3osIFQoMCksCgkJCQlUKDApLCBUKDApLCBUKDApLCBUKDEpIH07CgkJCXJldHVybiByOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZVNjYWxlIChUIHMpIHsKCQkJcmV0dXJuIENyZWF0ZVNjYWxlKHMsIHMsIHMpOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZVNjYWxlIChjb25zdCBUVmVjdG9yMzxUPiYgcykgewoJCQlyZXR1cm4gQ3JlYXRlU2NhbGUocy54LCBzLnksIHMueik7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2NhbGUgKFQgc3gsIFQgc3ksIFQgc3osIGNvbnN0IFRWZWN0b3IzPFQ+JiBvcmlnaW4pIHsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCXN4LCBUKDApLCBUKDApLCBvcmlnaW4ueCAqIChUKDEpIC0gc3gpLAoJCQkJVCgwKSwgc3ksIFQoMCksIG9yaWdpbi55ICogKFQoMSkgLSBzeSksCgkJCQlUKDApLCBUKDApLCBzeiwgb3JpZ2luLnogKiAoVCgxKSAtIHN6KSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2NhbGUgKFQgcywgY29uc3QgVFZlY3RvcjM8VD4mIG9yaWdpbikgewoJCQlyZXR1cm4gQ3JlYXRlU2NhbGUocywgcywgcywgb3JpZ2luKTsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVTY2FsZSAoY29uc3QgVFZlY3RvcjM8VD4mIHMsIGNvbnN0IFRWZWN0b3IzPFQ+JiBvcmlnaW4pIHsKCQkJcmV0dXJuIENyZWF0ZVNjYWxlKHMueCwgcy55LCBzLnosIG9yaWdpbik7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUmVmbGVjdGlvblggKCkgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJLVQoMSksIFQoMCksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDEpLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUmVmbGVjdGlvblkgKCkgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgxKSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIC1UKDEpLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUmVmbGVjdGlvblogKCkgewoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgxKSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMSksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDApLCAtVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUmVmbGVjdGlvbiAoY29uc3QgVFZlY3RvcjM8VD4mIG5vcm1hbCwgY29uc3QgVFZlY3RvcjM8VD4mIG9yaWdpbikgewoJCQlUIGRvdWJsZWRvdG5vcm1vcmlnaW4gPSAoKFQpMikgKiAobm9ybWFsLkRvdChvcmlnaW4pKTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMSkgLSAoKFQpMikgKiBub3JtYWxbMF0gKiBub3JtYWxbMF0sCgkJCQktKChUKTIpICogbm9ybWFsWzBdICogbm9ybWFsWzFdLAoJCQkJLSgoVCkyKSAqIG5vcm1hbFswXSAqIG5vcm1hbFsyXSwKCQkJCWRvdWJsZWRvdG5vcm1vcmlnaW4gKiBub3JtYWxbMF0sCgkJCQktKChUKTIpICogbm9ybWFsWzFdICogbm9ybWFsWzBdLAoJCQkJVCgxKSAtICgoVCkyKSAqIG5vcm1hbFsxXSAqIG5vcm1hbFsxXSwKCQkJCS0oKFQpMikgKiBub3JtYWxbMV0gKiBub3JtYWxbMl0sCgkJCQlkb3VibGVkb3Rub3Jtb3JpZ2luICogbm9ybWFsWzFdLAoJCQkJLSgoVCkyKSAqIG5vcm1hbFsyXSAqIG5vcm1hbFswXSwKCQkJCS0oKFQpMikgKiBub3JtYWxbMl0gKiBub3JtYWxbMV0sCgkJCQlUKDEpIC0gKChUKTIpICogbm9ybWFsWzJdICogbm9ybWFsWzJdLAoJCQkJZG91YmxlZG90bm9ybW9yaWdpbiAqIG5vcm1hbFsyXSwKCQkJCVQoMCksCgkJCQlUKDApLAoJCQkJVCgwKSwKCQkJCVQoMSkKCQkJfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlT2JsaXF1ZVByb2plY3Rpb24gKGNvbnN0IFRWZWN0b3IzPFQ+JiBub3JtYWwsIGNvbnN0IFRWZWN0b3IzPFQ+JiBvcmlnaW4sIGNvbnN0IFRWZWN0b3IzPFQ+JiBkaXJlY3Rpb24pIHsKCQkJVCBub3JtYWxkb3RkaXIgPSBub3JtYWwuRG90KGRpcmVjdGlvbik7CgkJCVQgbm9ybWFsZG90b3JpZ2luID0gbm9ybWFsLkRvdChvcmlnaW4pOwoKI2lmZGVmIEZVUlJPVklORUNPT1JESU5BVEVTWVNURU1fTEVGVEhBTkRFRAoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJZGlyZWN0aW9uWzBdICogbm9ybWFsWzBdIC0gbm9ybWFsZG90ZGlyLAoJCQkJZGlyZWN0aW9uWzBdICogbm9ybWFsWzFdLAoJCQkJZGlyZWN0aW9uWzBdICogbm9ybWFsWzJdLAoJCQkJLW5vcm1hbGRvdG9yaWdpbiAqIGRpcmVjdGlvblswXSwKCQkJCWRpcmVjdGlvblsxXSAqIG5vcm1hbFswXSwKCQkJCWRpcmVjdGlvblsxXSAqIG5vcm1hbFsxXSAtIG5vcm1hbGRvdGRpciwKCQkJCWRpcmVjdGlvblsxXSAqIG5vcm1hbFsyXSwKCQkJCS1ub3JtYWxkb3RvcmlnaW4gKiBkaXJlY3Rpb25bMV0sCgkJCQktZGlyZWN0aW9uWzJdICogbm9ybWFsWzBdLAoJCQkJLWRpcmVjdGlvblsyXSAqIG5vcm1hbFsxXSwKCQkJCS1kaXJlY3Rpb25bMl0gKiBub3JtYWxbMl0gLSBub3JtYWxkb3RkaXIsCgkJCQlub3JtYWxkb3RvcmlnaW4gKiBkaXJlY3Rpb25bMl0sCgkJCQlUKDApLAoJCQkJVCgwKSwKCQkJCVQoMCksCgkJCQktbm9ybWFsZG90ZGlyCgkJCX07CiNlbHNlCgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQlkaXJlY3Rpb25bMF0gKiBub3JtYWxbMF0gLSBub3JtYWxkb3RkaXIsCgkJCQlkaXJlY3Rpb25bMF0gKiBub3JtYWxbMV0sCgkJCQlkaXJlY3Rpb25bMF0gKiBub3JtYWxbMl0sCgkJCQktbm9ybWFsZG90b3JpZ2luICogZGlyZWN0aW9uWzBdLAoJCQkJZGlyZWN0aW9uWzFdICogbm9ybWFsWzBdLAoJCQkJZGlyZWN0aW9uWzFdICogbm9ybWFsWzFdIC0gbm9ybWFsZG90ZGlyLAoJCQkJZGlyZWN0aW9uWzFdICogbm9ybWFsWzJdLAoJCQkJLW5vcm1hbGRvdG9yaWdpbiAqIGRpcmVjdGlvblsxXSwKCQkJCWRpcmVjdGlvblsyXSAqIG5vcm1hbFswXSwKCQkJCWRpcmVjdGlvblsyXSAqIG5vcm1hbFsxXSwKCQkJCWRpcmVjdGlvblsyXSAqIG5vcm1hbFsyXSAtIG5vcm1hbGRvdGRpciwKCQkJCS1ub3JtYWxkb3RvcmlnaW4gKiBkaXJlY3Rpb25bMl0sCgkJCQlUKDApLAoJCQkJVCgwKSwKCQkJCVQoMCksCgkJCQktbm9ybWFsZG90ZGlyCgkJCX07CiNlbmRpZgoKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlT3J0aG9ncmFwaGljUHJvamVjdGlvbk9mZkNlbnRlciAoIFQgbGVmdCwgVCByaWdodCwgIFQgYm90dG9tLCAgVCB0b3AgKSB7CgkJCXJldHVybiBDcmVhdGVPcnRob2dyYXBoaWNQcm9qZWN0aW9uT2ZmQ2VudGVyKGxlZnQsIHJpZ2h0LCBib3R0b20sIHRvcCwgKFQpLTEsIChUKTEgKTsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVPcnRob2dyYXBoaWNQcm9qZWN0aW9uT2ZmQ2VudGVyICggVCBsZWZ0LCBUIHJpZ2h0LCAgVCBib3R0b20sICBUIHRvcCwgVCBuZWFycGxhbmUsIFQgZmFycGxhbmUgKSB7CiNpZmRlZiBGVVJST1ZJTkVDT09SRElOQVRFU1lTVEVNX0xFRlRIQU5ERUQKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMikgLyAocmlnaHQgLSBsZWZ0KSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMikgLyAodG9wIC0gYm90dG9tKSwgVCgwKSwgVCgwKSwKCQkJCS1UKDApLCAtVCgwKSwgVCgyKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksIC1UKDApLAoJCQkJLSAocmlnaHQgKyBsZWZ0KSAvIChyaWdodCAtIGxlZnQpLCAtICh0b3AgKyBib3R0b20pIC8gKHRvcCAtIGJvdHRvbSksIC0gKGZhcnBsYW5lICsgbmVhcnBsYW5lKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksIFQoMSkKCQkJfTsKI2Vsc2UKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMikgLyAocmlnaHQgLSBsZWZ0KSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMikgLyAodG9wIC0gYm90dG9tKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIC1UKDIpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwgVCgwKSwKCQkJCS0gKHJpZ2h0ICsgbGVmdCkgLyAocmlnaHQgLSBsZWZ0KSwgLSAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pLCAtIChmYXJwbGFuZSArIG5lYXJwbGFuZSkgLyAoZmFycGxhbmUgLSBuZWFycGxhbmUpLCBUKDEpCgkJCX07CiNlbmRpZgoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVPcnRob2dyYXBoaWNQcm9qZWN0aW9uICggVCBsZWZ0LCBUIHJpZ2h0LCAgVCBib3R0b20sICBUIHRvcCApIHsKI2lmZGVmIEZVUlJPVklORUNPT1JESU5BVEVTWVNURU1fTEVGVEhBTkRFRAoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgyKSAvIChyaWdodCAtIGxlZnQpLCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgyKSAvICh0b3AgLSBib3R0b20pLCBUKDApLCBUKDApLAoJCQkJLVQoMCksIC1UKDApLCBUKDEpLCAtVCgwKSwKCQkJCS0gKHJpZ2h0ICsgbGVmdCkgLyAocmlnaHQgLSBsZWZ0KSwgLSAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pLCBUKDApLCBUKDEpCgkJCX07CiNlbHNlCgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQlUKDIpIC8gKHJpZ2h0IC0gbGVmdCksIFQoMCksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDIpIC8gKHRvcCAtIGJvdHRvbSksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDApLCAtVCgxKSwgVCgwKSwKCQkJCS0gKHJpZ2h0ICsgbGVmdCkgLyAocmlnaHQgLSBsZWZ0KSwgLSAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pLCBUKDApLCBUKDEpCgkJCX07CiNlbmRpZgoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVQZXJzcGVjdGl2ZVByb2plY3Rpb24gKCBUIGxlZnQsIFQgcmlnaHQsIFQgYm90dG9tLCBUIHRvcCwgVCBuZWFycGxhbmUsIFQgZmFycGxhbmUgKSB7CiNpZmRlZiBGVVJST1ZJTkVDT09SRElOQVRFU1lTVEVNX0xFRlRIQU5ERUQKCQkJUk1hdHJpeDQ8VD4gPSByIHsKCQkJCShUKDIpICogbmVhcnBsYW5lKSAvIChyaWdodCAtIGxlZnQpLCBUKDApLCAocmlnaHQgKyBsZWZ0KSAvIChyaWdodCAtIGxlZnQpLCBUKDApLAoJCQkJCVQoMCksIChUKDIpICogbmVhcnBsYW5lKSAvICh0b3AgLSBib3R0b20pLCAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pLCBUKDApLAoJCQkJCS1UKDApLCAtVCgwKSwgKGZhcnBsYW5lICsgbmVhcnBsYW5lKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksIChUKDIpICogZmFycGxhbmUgKiBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwKCQkJCQlUKDApLCBUKDApLCAtVCgxKSwgVCgwKQoJCQl9OwojZWxzZQoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJKFQoMikgKiBuZWFycGxhbmUpIC8gKHJpZ2h0IC0gbGVmdCksIFQoMCksIChyaWdodCArIGxlZnQpIC8gKHJpZ2h0IC0gbGVmdCksIFQoMCksCgkJCQlUKDApLCAoVCgyKSAqIG5lYXJwbGFuZSkgLyAodG9wIC0gYm90dG9tKSwgKHRvcCArIGJvdHRvbSkgLyAodG9wIC0gYm90dG9tKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIC0oZmFycGxhbmUgKyBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwgLShUKDIpICogZmFycGxhbmUgKiBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwKCQkJCVQoMCksIFQoMCksIC1UKDEpLCBUKDApCgkJCX07CiNlbmRpZgoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVQZXJzcGVjdGl2ZVByb2plY3Rpb24gKCBUIGZvdnksIFQgYXNwZWN0LCBUIG5lYXJwbGFuZSwgVCBmYXJwbGFuZSkgewoJCQlUIHJhbmdlID0gTWF0aGVtYTxUPjo6VGFuKGZvdnkgLyBUKDIpKSAqIG5lYXJwbGFuZTsKCQkJVCBsZWZ0ID0gLXJhbmdlICogYXNwZWN0OwoJCQlUIHJpZ2h0ID0gcmFuZ2UgKiBhc3BlY3Q7CgkJCVQgYm90dG9tID0gLXJhbmdlOwoJCQlUIHRvcCA9IHJhbmdlOwojaWZkZWYgRlVSUk9WSU5FQ09PUkRJTkFURVNZU1RFTV9MRUZUSEFOREVECgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQkoVCgyKSAqIG5lYXJwbGFuZSkgLyAocmlnaHQgLSBsZWZ0KSwgVCgwKSwgKHJpZ2h0ICsgbGVmdCkgLyAocmlnaHQgLSBsZWZ0KSwgVCgwKSwKCQkJCVQoMCksIChUKDIpICogbmVhcnBsYW5lKSAvICh0b3AgLSBib3R0b20pLCAodG9wICsgYm90dG9tKSAvICh0b3AgLSBib3R0b20pLCBUKDApLAoJCQkJLVQoMCksIC1UKDApLCAoZmFycGxhbmUgKyBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwgKFQoMikgKiBmYXJwbGFuZSAqIG5lYXJwbGFuZSkgLyAoZmFycGxhbmUgLSBuZWFycGxhbmUpLAoJCQkJVCgwKSwgVCgwKSwgLVQoMSksIFQoMCkKCQkJfTsKI2Vsc2UKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCShUKDIpICogbmVhcnBsYW5lKSAvIChyaWdodCAtIGxlZnQpLCBUKDApLCAocmlnaHQgKyBsZWZ0KSAvIChyaWdodCAtIGxlZnQpLCBUKDApLAoJCQkJVCgwKSwgKFQoMikgKiBuZWFycGxhbmUpIC8gKHRvcCAtIGJvdHRvbSksICh0b3AgKyBib3R0b20pIC8gKHRvcCAtIGJvdHRvbSksIFQoMCksCgkJCQlUKDApLCBUKDApLCAtKGZhcnBsYW5lICsgbmVhcnBsYW5lKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksIC0oVCgyKSAqIGZhcnBsYW5lICogbmVhcnBsYW5lKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksCgkJCQlUKDApLCBUKDApLCAtVCgxKSwgVCgwKQoJCQl9OwojZW5kaWYKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlUGVyc3BlY3RpdmVGb1YgKCBUIGZvdiwgVCB3aWR0aCwgVCBoZWlnaHQsIFQgbmVhcnBsYW5lLCBUIGZhcnBsYW5lKSB7CgkJCVQgcmFkID0gKFQpTWF0aGVtYTxUPjo6UmFkaWFucyhmb3YpOwoJCQlUIGggPSBNYXRoZW1hPFQ+OjpDb3MoVCgwLjUpICogcmFkKSAvIE1hdGhlbWE8VD46OlNpbihUKDAuNSkgKiByYWQpOwoJCQlUIHcgPSBoICogaGVpZ2h0IC8gd2lkdGg7CgojaWZkZWYgRlVSUk9WSU5FQ09PUkRJTkFURVNZU1RFTV9MRUZUSEFOREVECgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQl3LCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgaCwgVCgwKSwgVCgwKSwKCQkJCS1UKDApLCAtVCgwKSwgKGZhcnBsYW5lICsgbmVhcnBsYW5lKSAvIChmYXJwbGFuZSAtIG5lYXJwbGFuZSksIChUKDIpICogZmFycGxhbmUgKiBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwKCQkJCVQoMCksIFQoMCksIC1UKDEpLCBUKDApCgkJCX07CiNlbHNlCgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQl3LCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgaCwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIC0oZmFycGxhbmUgKyBuZWFycGxhbmUpIC8gKGZhcnBsYW5lIC0gbmVhcnBsYW5lKSwgLVQoMSksCgkJCQlUKDApLCBUKDApLCAtKFQoMikgKiBmYXJwbGFuZSAqIG5lYXJwbGFuZSkgLyAoZmFycGxhbmUgLSBuZWFycGxhbmUpLCBUKDApCgkJCX07CiNlbmRpZgoJCQlyZXR1cm4gcjsKCQl9CgoJCXN0YXRpYyBSTWF0cml4NDxUPiBDcmVhdGVJbmZpbml0ZVBlcnNwZWN0aXZlIChUIGZvdnksIFQgYXNwZWN0LCBUIG5lYXJwbGFuZSkgewoJCQlUIHJhbmdlID0gTWF0aGVtYTxUPjo6VGFuKGZvdnkgLyBUKDIpKSAqIG5lYXJwbGFuZTsKCQkJVCBsZWZ0ID0gLXJhbmdlICogYXNwZWN0OwoJCQlUIHJpZ2h0ID0gcmFuZ2UgKiBhc3BlY3Q7CgkJCVQgYm90dG9tID0gLXJhbmdlOwoJCQlUIHRvcCA9IHJhbmdlOwoKI2lmZGVmIEZVUlJPVklORUNPT1JESU5BVEVTWVNURU1fTEVGVEhBTkRFRAoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJKFQoMikgKiBuZWFycGxhbmUpIC8gKHJpZ2h0IC0gbGVmdCksIFQoMCksIFQoMCksIFQoMCksCgkJCQlUKDApLCAoVCgyKSAqIG5lYXJwbGFuZSkgLyAodG9wIC0gYm90dG9tKSwgVCgwKSwgVCgwKSwKCQkJCS1UKDApLCAtVCgwKSwgVCgxKSwgVCgxKSwKCQkJCVQoMCksIFQoMCksIC1UKDIpICogbmVhcnBsYW5lLCBUKDApCgkJCX07CiNlbHNlCgkJCVJNYXRyaXg0PFQ+IHIgPSB7CgkJCQkoVCgyKSAqIG5lYXJwbGFuZSkgLyAocmlnaHQgLSBsZWZ0KSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIChUKDIpICogbmVhcnBsYW5lKSAvICh0b3AgLSBib3R0b20pLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgLVQoMSksIC1UKDEpLAoJCQkJVCgwKSwgVCgwKSwgLVQoMikgKiBuZWFycGxhbmUsIFQoMCkKCQkJfTsKI2VuZGlmCgkJCXJldHVybiByOwoJCX0KCgkJc3RhdGljIFJNYXRyaXg0PFQ+IENyZWF0ZUluZmluaXRlUGVyc3BlY3RpdmUyIChUIGZvdnksIFQgYXNwZWN0LCBUIG5lYXJwbGFuZSkgewoJCQlUIHJhbmdlID0gTWF0aGVtYTxUPjo6VGFuKChmb3Z5IC8gVCgyKSkpICogbmVhcnBsYW5lOwoJCQlUIGxlZnQgPSAtcmFuZ2UgKiBhc3BlY3Q7CgkJCVQgcmlnaHQgPSByYW5nZSAqIGFzcGVjdDsKCQkJVCBib3R0b20gPSAtcmFuZ2U7CgkJCVQgdG9wID0gcmFuZ2U7CiNpZmRlZiBGVVJST1ZJTkVDT09SRElOQVRFU1lTVEVNX0xFRlRIQU5ERUQKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCShUKDIpICogbmVhcnBsYW5lKSAvIChyaWdodCAtIGxlZnQpLCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgKFQoMikgKiBuZWFycGxhbmUpIC8gKHRvcCAtIGJvdHRvbSksIFQoMCksIFQoMCksCgkJCQktVCgwKSwgLVQoMCksIFQoMC4wMDAxKSArIFQoMSksIFQoMSksCgkJCQlUKDApLCBUKDApLCAoVCgwLjAwMDEpIC0gVCgyKSkgKiBuZWFycGxhbmUsIFQoMCkKCQkJfTsKI2Vsc2UKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCShUKDIpICogbmVhcnBsYW5lKSAvIChyaWdodCAtIGxlZnQpLCBUKDApLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgKFQoMikgKiBuZWFycGxhbmUpIC8gKHRvcCAtIGJvdHRvbSksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDApLCBUKDAuMDAwMSkgLSBUKDEpLCAtVCgxKSwKCQkJCVQoMCksIFQoMCksIChUKDAuMDAwMSkgLSBUKDIpKSAqIG5lYXJwbGFuZSwgVCgwKQoJCQl9OwojZW5kaWYKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlTG9va0F0ICggY29uc3QgVFZlY3RvcjM8VD4mIGV5ZSwgY29uc3QgVFZlY3RvcjM8VD4mIGNlbnRlciwgY29uc3QgVFZlY3RvcjM8VD4mIHVwKSB7CgkJCVRWZWN0b3IzPFQ+IGYgPSBUVmVjdG9yMzxUPjo6Tm9ybWFsaXplKGNlbnRlciAtIGV5ZSk7CgkJCVRWZWN0b3IzPFQ+IHUgPSBUVmVjdG9yMzxUPjo6Tm9ybWFsaXplKHVwKTsKCQkJVFZlY3RvcjM8VD4gcyA9IFRWZWN0b3IzPFQ+OjpOb3JtYWxpemUoZi5Dcm9zcyh1KSk7CgkJCXUgPSBzLkNyb3NzKGYpOwoKI2lmZGVmIEZVUlJPVklORUNPT1JESU5BVEVTWVNURU1fTEVGVEhBTkRFRAoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJcy54LCBzLnksIHMueiwgLXMuRG90KGV5ZSksCgkJCQl1LngsIHUueSwgdS56LCAtdS5Eb3QoZXllKSwKCQkJCWYueCwgZi55LCBmLnosIC1mLkRvdChleWUpLAoJCQkJVCgwKSwgVCgwKSwgVCgwKSwgVCgxKQoJCQl9OwojZWxzZQoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJcy54LCBzLnksIHMueiwgLXMuRG90KGV5ZSksCgkJCQl1LngsIHUueSwgdS56LCAtdS5Eb3QoZXllKSwKCQkJCWYueCwgZi55LCBmLnosIC1mLkRvdChleWUpLAoJCQkJVCgwKSwgVCgwKSwgVCgwKSwgVCgxKQoJCQl9OwojZW5kaWYKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJYIChUIGR5cmFkaWFucywgVCBkenJhZGlhbnMpIHsKCQkJZHlyYWRpYW5zID0gTWF0aGVtYTxUPjo6VGFuKGR5cmFkaWFucyk7CgkJCWR6cmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihkenJhZGlhbnMpOwoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgxKSwgZHlyYWRpYW5zLCBkenJhZGlhbnMsIFQoMCksCgkJCQlUKDApLCBUKDEpLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJYIChUIHJhZGlhbnMpIHsKCQkJcmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihyYWRpYW5zKTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMSksIHJhZGlhbnMsIHJhZGlhbnMsIFQoMCksCgkJCQlUKDApLCBUKDEpLCBUKDApLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJZIChUIHJhZGlhbnMpIHsKCQkJcmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihyYWRpYW5zKTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMSksIFQoMCksIFQoMCksIFQoMCksCgkJCQlyYWRpYW5zLCBUKDEpLCByYWRpYW5zLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJZIChUIGR4cmFkaWFucywgVCBkenJhZGlhbnMpIHsKCQkJZHhyYWRpYW5zID0gTWF0aGVtYTxUPjo6VGFuKGR4cmFkaWFucyk7CgkJCWR6cmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihkenJhZGlhbnMpOwoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgxKSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCWR4cmFkaWFucywgVCgxKSwgZHpyYWRpYW5zLCBUKDApLAoJCQkJVCgwKSwgVCgwKSwgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJaIChUIHJhZGlhbnMpIHsKCQkJcmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihyYWRpYW5zKTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMSksIFQoMCksIFQoMCksIFQoMCksCgkJCQlUKDApLCBUKDEpLCBUKDApLCBUKDApLAoJCQkJcmFkaWFucywgcmFkaWFucywgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXJaIChUIGR4cmFkaWFucywgVCBkeXJhZGlhbnMpIHsKCQkJZHhyYWRpYW5zID0gTWF0aGVtYTxUPjo6VGFuKGR4cmFkaWFucyk7CgkJCWR5cmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbihkeXJhZGlhbnMpOwoJCQlSTWF0cml4NDxUPiByID0gewoJCQkJVCgxKSwgVCgwKSwgVCgwKSwgVCgwKSwKCQkJCVQoMCksIFQoMSksIFQoMCksIFQoMCksCgkJCQlkeHJhZGlhbnMsIGR5cmFkaWFucywgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXIgKFQgeHJhZGlhbnMgPSBUKDApLCBUIHlyYWRpYW5zID0gVCgwKSwgVCB6cmFkaWFucyA9IFQoMCkpIHsKCQkJeHJhZGlhbnMgPSBNYXRoZW1hPFQ+OjpUYW4oeHJhZGlhbnMpOwoJCQl5cmFkaWFucyA9IE1hdGhlbWE8VD46OlRhbih5cmFkaWFucyk7CgkJCXpyYWRpYW5zID0gTWF0aGVtYTxUPjo6VGFuKHpyYWRpYW5zKTsKCQkJUk1hdHJpeDQ8VD4gciA9IHsKCQkJCVQoMSksIHhyYWRpYW5zLCB4cmFkaWFucywgVCgwKSwKCQkJCXlyYWRpYW5zLCBUKDEpLCB5cmFkaWFucywgVCgwKSwKCQkJCXpyYWRpYW5zLCB6cmFkaWFucywgVCgxKSwgVCgwKSwKCQkJCVQoMCksIFQoMCksIFQoMCksIFQoMSkgfTsKCQkJcmV0dXJuIHI7CgkJfQoKCQlzdGF0aWMgUk1hdHJpeDQ8VD4gQ3JlYXRlU2hlYXIgKGNvbnN0IFRWZWN0b3IzPFQ+JiByYWRpYW5zKSB7CgkJCXJldHVybiBDcmVhdGVTaGVhcihyYWRpYW5zLngsIHJhZGlhbnMueSwgcmFkaWFucy56KTsKCQl9CgoJfTsKCn0KCiNlbmRpZiAvKiBGVVJST1ZJTkVSTUFUUklYNF9IICov