#include<vector>
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2/imgproc/imgproc.hpp>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<omp.h>
using namespace cv;
using namespace std;
Scalar meanpixel( Mat matrx)
{
Scalar meanpix;
#pragma omp parallel for
for ( int i= 0 ; i< matrx.rows ; i++ )
{
for ( int j= 0 ; j< matrx.cols ; j++ )
{
meanpix[ 0 ] = meanpix[ 0 ] + double ( matrx.at < Vec3b> ( i,j) [ 0 ] ) ;
meanpix[ 1 ] = meanpix[ 1 ] + double ( matrx.at < Vec3b> ( i,j) [ 1 ] ) ;
meanpix[ 2 ] = meanpix[ 2 ] + double ( matrx.at < Vec3b> ( i,j) [ 2 ] ) ;
}
}
meanpix[ 0 ] = floor ( ( meanpix[ 0 ] / ( matrx.rows * matrx.cols ) ) + 0.5 ) ;
meanpix[ 1 ] = floor ( ( meanpix[ 1 ] / ( matrx.rows * matrx.cols ) ) + 0.5 ) ;
meanpix[ 2 ] = floor ( ( meanpix[ 2 ] / ( matrx.rows * matrx.cols ) ) + 0.5 ) ;
return meanpix;
}
Mat covarmatrixcal( Mat matrx1, Scalar meanscal)
{
double rr= 0 ,rg= 0 ,rb= 0 ,gr= 0 ,gg= 0 ,gb= 0 ,br= 0 ,bg= 0 ,bb= 0 ;
int k= 0 ;
k= ( matrx1.rows * matrx1.cols ) ;
Vec3b temp1;
#pragma omp parallel for
for ( int i = 0 ; i < matrx1.rows ; i++ )
{
for ( int j= 0 ; j< matrx1.cols ; j++ )
{
temp1= matrx1.at < Vec3b> ( i,j) ;
rr= rr+ ( ( double ( temp1[ 0 ] ) - meanscal[ 0 ] ) * ( double ( temp1[ 0 ] ) - meanscal[ 0 ] ) ) ;
rg= rg+ ( ( double ( temp1[ 0 ] ) - meanscal[ 0 ] ) * ( double ( temp1[ 1 ] ) - meanscal[ 1 ] ) ) ;
rb= rb+ ( ( double ( temp1[ 0 ] ) - meanscal[ 0 ] ) * ( double ( temp1[ 2 ] ) - meanscal[ 2 ] ) ) ;
gg= gg+ ( ( double ( temp1[ 1 ] ) - meanscal[ 1 ] ) * ( double ( temp1[ 1 ] ) - meanscal[ 1 ] ) ) ;
gb= gb+ ( ( double ( temp1[ 1 ] ) - meanscal[ 1 ] ) * ( double ( temp1[ 2 ] ) - meanscal[ 2 ] ) ) ;
bb= bb+ ( ( double ( temp1[ 2 ] ) - meanscal[ 2 ] ) * ( double ( temp1[ 2 ] ) - meanscal[ 2 ] ) ) ;
}
}
rr= rr/ ( k- 1 ) ;
rg= rg/ ( k- 1 ) ;
rb= rb/ ( k- 1 ) ;
gr= rg;
gg= gg/ ( k- 1 ) ;
gb= gb/ ( k- 1 ) ;
br= rb;
bg= gb;
bb= bb/ ( k- 1 ) ;
double m[ 3 ] [ 3 ] = { { rr,rg,rb} ,{ gr,gg,gb} ,{ br,bg,bb} } ;
Mat covmatrix( 3 ,3 ,CV_64F,m) ;
return covmatrix.clone ( ) ;
}
double mahadistance( Mat invcov, Scalar meanvec, Vec3b patternvec)
{
double distmeasure= 0 ;
Scalar x1,x2;
//mahalanobis distance is equal to (x-mean)^T*inv(cov)*(x-mean)
x1[ 0 ] = ( patternvec[ 0 ] - meanvec[ 0 ] ) ;
x1[ 1 ] = ( patternvec[ 1 ] - meanvec[ 1 ] ) ;
x1[ 2 ] = ( patternvec[ 2 ] - meanvec[ 2 ] ) ;
#pragma omp parallel for
for ( int k = 0 ; k < 3 ; k++ )
{
x2[ 0 ] = x2[ 0 ] + ( x1[ k] * invcov.at < double > ( k,0 ) ) ;
x2[ 1 ] = x2[ 1 ] + ( x1[ k] * invcov.at < double > ( k,1 ) ) ;
x2[ 2 ] = x2[ 2 ] + ( x1[ k] * invcov.at < double > ( k,2 ) ) ;
}
distmeasure= ( ( x2[ 0 ] * x1[ 0 ] ) + ( x2[ 1 ] * x1[ 1 ] ) + ( x2[ 2 ] * x1[ 2 ] ) ) ;
return distmeasure;
}
Mat inversemat( Mat matrx)
{
double determ;
determ = ( matrx.at < double > ( 0 ,0 ) * ( ( matrx.at < double > ( 1 ,1 ) * matrx.at < double > ( 2 ,2 ) ) - ( matrx.at < double > ( 1 ,2 ) * matrx.at < double > ( 2 ,1 ) ) ) ) - ( matrx.at < double > ( 0 ,1 ) * ( ( matrx.at < double > ( 1 ,0 ) * matrx.at < double > ( 2 ,2 ) ) - ( matrx.at < double > ( 2 ,0 ) * matrx.at < double > ( 1 ,2 ) ) ) ) + ( matrx.at < double > ( 0 ,2 ) * ( ( matrx.at < double > ( 1 ,0 ) * matrx.at < double > ( 2 ,1 ) ) - ( matrx.at < double > ( 1 ,1 ) * matrx.at < double > ( 2 ,0 ) ) ) ) ;
Mat mt= matrx.t ( ) ;
double m11,m12,m13,m21,m22,m23,m31,m32,m33;
m11= ( mt.at < double > ( 1 ,1 ) * mt.at < double > ( 2 ,2 ) ) - ( mt.at < double > ( 2 ,1 ) * mt.at < double > ( 1 ,2 ) ) ;
m12= ( mt.at < double > ( 1 ,0 ) * mt.at < double > ( 2 ,2 ) ) - ( mt.at < double > ( 2 ,0 ) * mt.at < double > ( 1 ,2 ) ) ;
m13= ( mt.at < double > ( 1 ,0 ) * mt.at < double > ( 2 ,1 ) ) - ( mt.at < double > ( 2 ,0 ) * mt.at < double > ( 1 ,1 ) ) ;
m21= ( mt.at < double > ( 0 ,1 ) * mt.at < double > ( 2 ,2 ) ) - ( mt.at < double > ( 2 ,1 ) * mt.at < double > ( 0 ,2 ) ) ;
m22= ( mt.at < double > ( 0 ,0 ) * mt.at < double > ( 2 ,2 ) ) - ( mt.at < double > ( 2 ,0 ) * mt.at < double > ( 0 ,2 ) ) ;
m23= ( mt.at < double > ( 0 ,0 ) * mt.at < double > ( 2 ,1 ) ) - ( mt.at < double > ( 2 ,0 ) * mt.at < double > ( 0 ,1 ) ) ;
m31= ( mt.at < double > ( 0 ,1 ) * mt.at < double > ( 1 ,2 ) ) - ( mt.at < double > ( 1 ,1 ) * mt.at < double > ( 0 ,2 ) ) ;
m32= ( mt.at < double > ( 0 ,0 ) * mt.at < double > ( 1 ,2 ) ) - ( mt.at < double > ( 1 ,0 ) * mt.at < double > ( 0 ,2 ) ) ;
m33= ( mt.at < double > ( 0 ,0 ) * mt.at < double > ( 1 ,1 ) ) - ( mt.at < double > ( 1 ,0 ) * mt.at < double > ( 0 ,1 ) ) ;
double imat[ 3 ] [ 3 ] = { { ( m11/ determ) ,( - m12/ determ) ,( m13/ determ) } ,{ ( - m21/ determ) ,( m22/ determ) ,( - m23/ determ) } ,{ ( m31/ determ) ,( - m32/ determ) ,( m33/ determ) } } ;
Mat invmat( 3 ,3 ,CV_64F,imat) ;
return invmat.clone ( ) ; //as only the address to where the data is stored is passed to the function the object is destroyed so an empty matrix is returned with initial values -9.23842e+61
}
Mat imagesegmentation( Mat image, Mat icovar, Scalar meanmat,double distance, Mat mask, Mat element)
{
#pragma omp parallel for
for ( int i = 0 ; i < image.rows ; i++ )
{
for ( int j= 0 ; j< image.cols ; j++ ) //in case it fails changed it from i=1 to i=0
{
Vec3b pixel= image.at < Vec3b> ( i,j) ; //prints wierd characters
double mdist= mahadistance( icovar,meanmat,pixel) ;
if ( mdist< distance)
mask.at < uchar> ( i,j) = 255 ;
else
mask.at < uchar> ( i,j) = 0 ;
}
}
Mat mask1= mask;
morphologyEx( mask,mask1,2 ,element) ;
return mask;
}
Mat Cornerdetect( Mat image, Mat corners,int numcorners)
{
Mat grayscale;
#pragma omp parallel sections
{
#pragma omp section
{ cvtColor( image,grayscale,CV_BGR2GRAY) ; }
//goodfeatures(grayimage, output to store corners, quality factor, distance factor)
#pragma omp section
{ goodFeaturesToTrack( grayscale,corners,numcorners,0.01 ,70 ) ; }
// Mark these corners on the original image
}
if ( corners.rows ! = 0 )
{
cornerSubPix( grayscale, corners, Size( 11 , 11 ) , Size( - 1 , - 1 ) , TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30 , 0.1 ) ) ;
}
return corners;
}
I2luY2x1ZGU8dmVjdG9yPgojaW5jbHVkZTxvcGVuY3ZcY3YuaD4KI2luY2x1ZGU8b3BlbmN2XGhpZ2hndWkuaD4KI2luY2x1ZGU8b3BlbmN2Mi9pbWdwcm9jL2ltZ3Byb2MuaHBwPgojaW5jbHVkZTxjc3RkbGliPgojaW5jbHVkZTxpb3N0cmVhbT4KI2luY2x1ZGU8Y21hdGg+CiNpbmNsdWRlPG9tcC5oPgoKdXNpbmcgbmFtZXNwYWNlIGN2Owp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKU2NhbGFyIG1lYW5waXhlbChNYXQgbWF0cngpCnsKICAgIFNjYWxhciBtZWFucGl4OwoKCSNwcmFnbWEgb21wIHBhcmFsbGVsIGZvcgoJZm9yKGludCBpPTA7aTxtYXRyeC5yb3dzO2krKykKCXsKCQlmb3IoaW50IGo9MDtqPG1hdHJ4LmNvbHM7aisrKQoJCXsKCQkJbWVhbnBpeFswXT1tZWFucGl4WzBdK2RvdWJsZShtYXRyeC5hdDxWZWMzYj4oaSxqKVswXSk7CgkJCW1lYW5waXhbMV09bWVhbnBpeFsxXStkb3VibGUobWF0cnguYXQ8VmVjM2I+KGksailbMV0pOwoJCQltZWFucGl4WzJdPW1lYW5waXhbMl0rZG91YmxlKG1hdHJ4LmF0PFZlYzNiPihpLGopWzJdKTsKCQl9Cgl9CgltZWFucGl4WzBdPWZsb29yKChtZWFucGl4WzBdLyhtYXRyeC5yb3dzKm1hdHJ4LmNvbHMpKSswLjUpOwoJbWVhbnBpeFsxXT1mbG9vcigobWVhbnBpeFsxXS8obWF0cngucm93cyptYXRyeC5jb2xzKSkrMC41KTsKCW1lYW5waXhbMl09Zmxvb3IoKG1lYW5waXhbMl0vKG1hdHJ4LnJvd3MqbWF0cnguY29scykpKzAuNSk7CglyZXR1cm4gbWVhbnBpeDsKfQoKTWF0IGNvdmFybWF0cml4Y2FsKE1hdCBtYXRyeDEsIFNjYWxhciBtZWFuc2NhbCkKewoKCWRvdWJsZSBycj0wLHJnPTAscmI9MCxncj0wLGdnPTAsZ2I9MCxicj0wLGJnPTAsYmI9MDsKCWludCBrPTA7CglrPShtYXRyeDEucm93cyptYXRyeDEuY29scyk7CglWZWMzYiB0ZW1wMTsKCSNwcmFnbWEgb21wIHBhcmFsbGVsIGZvcgoJZm9yKGludCBpID0gMDsgaSA8IG1hdHJ4MS5yb3dzO2krKykKCXsKCQlmb3IoaW50IGo9MDtqPG1hdHJ4MS5jb2xzO2orKykKCQl7CgkJCXRlbXAxPW1hdHJ4MS5hdDxWZWMzYj4oaSxqKTsKCQkJcnI9cnIrKChkb3VibGUodGVtcDFbMF0pLW1lYW5zY2FsWzBdKSooZG91YmxlKHRlbXAxWzBdKS1tZWFuc2NhbFswXSkpOwoJCQlyZz1yZysoKGRvdWJsZSh0ZW1wMVswXSktbWVhbnNjYWxbMF0pKihkb3VibGUodGVtcDFbMV0pLW1lYW5zY2FsWzFdKSk7CgkJCXJiPXJiKygoZG91YmxlKHRlbXAxWzBdKS1tZWFuc2NhbFswXSkqKGRvdWJsZSh0ZW1wMVsyXSktbWVhbnNjYWxbMl0pKTsKCQkJZ2c9Z2crKChkb3VibGUodGVtcDFbMV0pLW1lYW5zY2FsWzFdKSooZG91YmxlKHRlbXAxWzFdKS1tZWFuc2NhbFsxXSkpOwoJCQlnYj1nYisoKGRvdWJsZSh0ZW1wMVsxXSktbWVhbnNjYWxbMV0pKihkb3VibGUodGVtcDFbMl0pLW1lYW5zY2FsWzJdKSk7CgkJCWJiPWJiKygoZG91YmxlKHRlbXAxWzJdKS1tZWFuc2NhbFsyXSkqKGRvdWJsZSh0ZW1wMVsyXSktbWVhbnNjYWxbMl0pKTsKCQl9Cgl9Cglycj1yci8oay0xKTsKCXJnPXJnLyhrLTEpOwoJcmI9cmIvKGstMSk7Cglncj1yZzsKCWdnPWdnLyhrLTEpOwoJZ2I9Z2IvKGstMSk7Cglicj1yYjsKCWJnPWdiOwoJYmI9YmIvKGstMSk7CgoJZG91YmxlIG1bM11bM109e3tycixyZyxyYn0se2dyLGdnLGdifSx7YnIsYmcsYmJ9fTsKCglNYXQgY292bWF0cml4KDMsMyxDVl82NEYsbSk7CglyZXR1cm4gY292bWF0cml4LmNsb25lKCk7Cgp9Cgpkb3VibGUgbWFoYWRpc3RhbmNlKE1hdCBpbnZjb3YsIFNjYWxhciBtZWFudmVjLCBWZWMzYiBwYXR0ZXJudmVjKQp7Cglkb3VibGUgZGlzdG1lYXN1cmU9MDsKCVNjYWxhciB4MSx4MjsKCQoJLy9tYWhhbGFub2JpcyBkaXN0YW5jZSBpcyBlcXVhbCB0byAoeC1tZWFuKV5UKmludihjb3YpKih4LW1lYW4pCgl4MVswXT0ocGF0dGVybnZlY1swXS1tZWFudmVjWzBdKTsKCXgxWzFdPShwYXR0ZXJudmVjWzFdLW1lYW52ZWNbMV0pOwoJeDFbMl09KHBhdHRlcm52ZWNbMl0tbWVhbnZlY1syXSk7CgkKCSNwcmFnbWEgb21wIHBhcmFsbGVsIGZvcgoJZm9yKGludCBrID0gMDsgayA8IDM7aysrKQoJewoJCXgyWzBdPXgyWzBdKyh4MVtrXSppbnZjb3YuYXQ8ZG91YmxlPihrLDApKTsKCQl4MlsxXT14MlsxXSsoeDFba10qaW52Y292LmF0PGRvdWJsZT4oaywxKSk7ICAKCQl4MlsyXT14MlsyXSsoeDFba10qaW52Y292LmF0PGRvdWJsZT4oaywyKSk7Cgl9CgoJZGlzdG1lYXN1cmU9KCh4MlswXSp4MVswXSkrKHgyWzFdKngxWzFdKSsoeDJbMl0qeDFbMl0pKTsKCXJldHVybiBkaXN0bWVhc3VyZTsKfQoKTWF0IGludmVyc2VtYXQoTWF0IG1hdHJ4KQp7Cglkb3VibGUgZGV0ZXJtOwoJZGV0ZXJtID0gKG1hdHJ4LmF0PGRvdWJsZT4oMCwwKSooKG1hdHJ4LmF0PGRvdWJsZT4oMSwxKSptYXRyeC5hdDxkb3VibGU+KDIsMikpLShtYXRyeC5hdDxkb3VibGU+KDEsMikqbWF0cnguYXQ8ZG91YmxlPigyLDEpKSkpLShtYXRyeC5hdDxkb3VibGU+KDAsMSkqKChtYXRyeC5hdDxkb3VibGU+KDEsMCkqbWF0cnguYXQ8ZG91YmxlPigyLDIpKS0obWF0cnguYXQ8ZG91YmxlPigyLDApKm1hdHJ4LmF0PGRvdWJsZT4oMSwyKSkpKSsobWF0cnguYXQ8ZG91YmxlPigwLDIpKigobWF0cnguYXQ8ZG91YmxlPigxLDApKm1hdHJ4LmF0PGRvdWJsZT4oMiwxKSktKG1hdHJ4LmF0PGRvdWJsZT4oMSwxKSptYXRyeC5hdDxkb3VibGU+KDIsMCkpKSk7CglNYXQgbXQ9bWF0cngudCgpOwoJZG91YmxlIG0xMSxtMTIsbTEzLG0yMSxtMjIsbTIzLG0zMSxtMzIsbTMzOwoJbTExPShtdC5hdDxkb3VibGU+KDEsMSkqbXQuYXQ8ZG91YmxlPigyLDIpKS0obXQuYXQ8ZG91YmxlPigyLDEpKm10LmF0PGRvdWJsZT4oMSwyKSk7CgltMTI9KG10LmF0PGRvdWJsZT4oMSwwKSptdC5hdDxkb3VibGU+KDIsMikpLShtdC5hdDxkb3VibGU+KDIsMCkqbXQuYXQ8ZG91YmxlPigxLDIpKTsKCW0xMz0obXQuYXQ8ZG91YmxlPigxLDApKm10LmF0PGRvdWJsZT4oMiwxKSktKG10LmF0PGRvdWJsZT4oMiwwKSptdC5hdDxkb3VibGU+KDEsMSkpOwoJbTIxPShtdC5hdDxkb3VibGU+KDAsMSkqbXQuYXQ8ZG91YmxlPigyLDIpKS0obXQuYXQ8ZG91YmxlPigyLDEpKm10LmF0PGRvdWJsZT4oMCwyKSk7CgltMjI9KG10LmF0PGRvdWJsZT4oMCwwKSptdC5hdDxkb3VibGU+KDIsMikpLShtdC5hdDxkb3VibGU+KDIsMCkqbXQuYXQ8ZG91YmxlPigwLDIpKTsKCW0yMz0obXQuYXQ8ZG91YmxlPigwLDApKm10LmF0PGRvdWJsZT4oMiwxKSktKG10LmF0PGRvdWJsZT4oMiwwKSptdC5hdDxkb3VibGU+KDAsMSkpOwoJbTMxPShtdC5hdDxkb3VibGU+KDAsMSkqbXQuYXQ8ZG91YmxlPigxLDIpKS0obXQuYXQ8ZG91YmxlPigxLDEpKm10LmF0PGRvdWJsZT4oMCwyKSk7CgltMzI9KG10LmF0PGRvdWJsZT4oMCwwKSptdC5hdDxkb3VibGU+KDEsMikpLShtdC5hdDxkb3VibGU+KDEsMCkqbXQuYXQ8ZG91YmxlPigwLDIpKTsKCW0zMz0obXQuYXQ8ZG91YmxlPigwLDApKm10LmF0PGRvdWJsZT4oMSwxKSktKG10LmF0PGRvdWJsZT4oMSwwKSptdC5hdDxkb3VibGU+KDAsMSkpOwoKCWRvdWJsZSBpbWF0WzNdWzNdPXt7KG0xMS9kZXRlcm0pLCgtbTEyL2RldGVybSksKG0xMy9kZXRlcm0pfSx7KC1tMjEvZGV0ZXJtKSwobTIyL2RldGVybSksKC1tMjMvZGV0ZXJtKX0seyhtMzEvZGV0ZXJtKSwoLW0zMi9kZXRlcm0pLChtMzMvZGV0ZXJtKX19OwoJTWF0IGludm1hdCgzLDMsQ1ZfNjRGLGltYXQpOwoJcmV0dXJuIGludm1hdC5jbG9uZSgpOwkvL2FzIG9ubHkgdGhlIGFkZHJlc3MgdG8gd2hlcmUgdGhlIGRhdGEgaXMgc3RvcmVkIGlzIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24gdGhlIG9iamVjdCBpcyBkZXN0cm95ZWQgc28gYW4gZW1wdHkgbWF0cml4IGlzIHJldHVybmVkIHdpdGggaW5pdGlhbCB2YWx1ZXMgLTkuMjM4NDJlKzYxCn0KCk1hdCBpbWFnZXNlZ21lbnRhdGlvbihNYXQgaW1hZ2UsIE1hdCBpY292YXIsIFNjYWxhciBtZWFubWF0LGRvdWJsZSBkaXN0YW5jZSwgTWF0IG1hc2ssIE1hdCBlbGVtZW50KQp7CQogICAjcHJhZ21hIG9tcCBwYXJhbGxlbCBmb3IKICAgIGZvcihpbnQgaSA9IDA7IGkgPCBpbWFnZS5yb3dzO2krKykKICAgIHsKICAgICAgICBmb3IoaW50IGo9MDsgajxpbWFnZS5jb2xzO2orKykJLy9pbiBjYXNlIGl0IGZhaWxzIGNoYW5nZWQgaXQgZnJvbSBpPTEgdG8gaT0wCgkJewoJCQlWZWMzYiBwaXhlbD0gaW1hZ2UuYXQ8VmVjM2I+KGksaik7CS8vcHJpbnRzIHdpZXJkIGNoYXJhY3RlcnMKCQkJZG91YmxlIG1kaXN0PW1haGFkaXN0YW5jZShpY292YXIsbWVhbm1hdCxwaXhlbCk7CgkJCWlmKG1kaXN0PGRpc3RhbmNlKQoJCQkJbWFzay5hdDx1Y2hhcj4oaSxqKT0yNTU7CgkJCWVsc2UKCQkJCW1hc2suYXQ8dWNoYXI+KGksaik9MDsKCQl9CiAgICB9CglNYXQgbWFzazE9bWFzazsKCW1vcnBob2xvZ3lFeChtYXNrLG1hc2sxLDIsZWxlbWVudCk7CiAgICByZXR1cm4gbWFzazsKfQoKTWF0IENvcm5lcmRldGVjdChNYXQgaW1hZ2UsIE1hdCBjb3JuZXJzLGludCBudW1jb3JuZXJzKQp7CglNYXQgZ3JheXNjYWxlOwoJI3ByYWdtYSBvbXAgcGFyYWxsZWwgc2VjdGlvbnMKCXsJCgkJI3ByYWdtYSBvbXAgc2VjdGlvbiAKCQl7IGN2dENvbG9yKGltYWdlLGdyYXlzY2FsZSxDVl9CR1IyR1JBWSk7IH0KCQkvL2dvb2RmZWF0dXJlcyhncmF5aW1hZ2UsIG91dHB1dCB0byBzdG9yZSBjb3JuZXJzLCBxdWFsaXR5IGZhY3RvciwgZGlzdGFuY2UgZmFjdG9yKQoJCSNwcmFnbWEgb21wIHNlY3Rpb24gCgkJeyBnb29kRmVhdHVyZXNUb1RyYWNrKGdyYXlzY2FsZSxjb3JuZXJzLG51bWNvcm5lcnMsMC4wMSw3MCk7IH0gICAKCQkvLyBNYXJrIHRoZXNlIGNvcm5lcnMgb24gdGhlIG9yaWdpbmFsIGltYWdlCgl9CgkKCWlmKGNvcm5lcnMucm93cyE9MCkKCXsKCQljb3JuZXJTdWJQaXgoZ3JheXNjYWxlLCBjb3JuZXJzLCBTaXplKDExLCAxMSksIFNpemUoLTEsIC0xKSwgVGVybUNyaXRlcmlhKENWX1RFUk1DUklUX0VQUyB8IENWX1RFUk1DUklUX0lURVIsIDMwLCAwLjEpKTsgCgl9CglyZXR1cm4gY29ybmVyczsgCn0K