////////////////////////////////////////////////////////////////////////
// This font class was created by Azorbix (Matthew L) for Game-Deception
// http://w...content-available-to-author-only...n.com http://f...content-available-to-author-only...n.com
// irc://irc.rizon.net/game-deception
//
// A lot all of the CD3DFont::Initialize() code was created by Microsoft
// (taken from the D3D9 SDK)
//
// Please note that this is NOT 100% complete yet, colour tags and
// shadows are not implemented yet
//
// USAGE:
// CD3DFont:
// 1) Instanciate the class with the parameterized constructor
// eg CD3DFont *g_pD3Dfont = new CD3DFont("Arial", 16, FCT_BOLD);
//
// 2) Call Initialize() after other rendering is ready
// eg g_pD3DFont->Initialize(pD3Ddevice);
//
// 3) To begin rendering use Print function
// eg g_pD3DFont->Print(10.0f, 50.0f, 0xFF00FF00, "Hello World", FT_BORDER);
//
// 4) call Invalidate() upon Reset of the D3D surface and re-initialize
//
// CD3DRender:
// 1) Instanciate the class with the parameterized constructor
// eg CD3DRender *g_pRender = new CD3DRender(128);
//
// 2) Call Initialize() after other rendering is ready
// eg g_pRender->Initialize(pD3Ddevice);
//
// 3) To begin rendering, start rendering much like OpenGL
// eg if( SUCCEEDED(g_pRender->Begin(D3DPT_TRIANGLELIST)) )
// {
// D3DAddQuad(g_pRender, 10.0f, 10.0f, 50.0f, 50.0f, 0xFFFF0000); //helper function
// g_pRender->D3DColour(0xFF0000FF); //blue
// g_pRender->D3DVertex2f(60.0f, 60.0f);
// g_pRender->D3DVertex2f(60.0f, 110.0f);
// g_pRender->D3DVertex2f(110.0f, 110.0f);
// g_pRender->End();
// }
//
// 4) call Invalidate() upon Reset of the D3D surface and re-initialize
//
// FASTER RENDERING (Advanced but NOT REQUIRED):
// To enable faster rendering, it's ideal to call static function CD3DBaseRendering::BeginRender(); before
// other font / primitive rendering code, and call CD3DBaseRendering::EndRender(); afterwards
// *** IT IS CRUCIAL THAT YOU CALL EndRender FOR EVERY BeginRender() CALL ***
// *** IMAGE RENDERING MAY BECOME CORRUPT IF YOU DO NOT ***
// eg
// if( SUCCEEDED(CD3DBaseRender::BeginRender()) )
// {
// //primitive and font rendering goes here
// CD3DBaseRender::EndRender();
// }
//
#include "main.h"
#include "cd3dfont.h"
IDirect3DDevice9 *CD3DBaseRender:: m_pD3Ddev = NULL;
IDirect3DStateBlock9 *CD3DBaseRender:: m_pD3DstateDraw = NULL;
IDirect3DStateBlock9 *CD3DBaseRender:: m_pD3DstateNorm = NULL;
int CD3DBaseRender:: m_renderCount = 0;
int CD3DBaseRender:: m_numShared = 0;
bool CD3DBaseRender:: m_statesOK = false;
inline d3dvertex_s Init2DVertex ( float x, float y, DWORD color, float tu, float tv )
{
d3dvertex_s v = { x, y, 1.0f, 1.0f, color, tu, tv };
return v;
}
CD3DBaseRender::CD3DBaseRender ()
{
m_numShared++;
}
CD3DBaseRender::~CD3DBaseRender ()
{
if ( --m_numShared == 0 )
DeleteStates();
}
HRESULT CD3DBaseRender::Initialize ( IDirect3DDevice9 *pD3Ddev )
{
if ( m_pD3Ddev == NULL && (m_pD3Ddev = pD3Ddev) == NULL )
return E_FAIL;
if ( !m_statesOK && FAILED(CreateStates()) )
return E_FAIL;
return S_OK;
}
HRESULT CD3DBaseRender::Invalidate ()
{
DeleteStates();
return S_OK;
}
HRESULT CD3DBaseRender::BeginRender ()
{
if ( !m_statesOK )
return E_FAIL;
if ( ++m_renderCount == 1 )
{
__try
{
m_pD3DstateNorm->Capture();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
--m_renderCount;
return E_FAIL;
}
m_pD3DstateDraw->Apply();
}
return S_OK;
}
HRESULT CD3DBaseRender::EndRender ()
{
if ( !m_statesOK )
return E_FAIL;
m_renderCount--;
if ( m_renderCount == 0 )
m_pD3DstateNorm->Apply();
else if ( m_renderCount < 0 )
m_renderCount = 0;
return S_OK;
}
HRESULT CD3DBaseRender::CreateStates ()
{
for ( int iStateBlock = 0; iStateBlock < 2; iStateBlock++ )
{
m_pD3Ddev->BeginStateBlock();
m_pD3Ddev->SetPixelShader( NULL );
m_pD3Ddev->SetVertexShader( NULL );
m_pD3Ddev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pD3Ddev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pD3Ddev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
m_pD3Ddev->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE );
m_pD3Ddev->SetRenderState( D3DRS_ALPHAREF, 0x08 );
m_pD3Ddev->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
m_pD3Ddev->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
m_pD3Ddev->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
m_pD3Ddev->SetRenderState( D3DRS_STENCILENABLE, FALSE );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, TRUE );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE );
m_pD3Ddev->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_DISABLE );
m_pD3Ddev->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );
m_pD3Ddev->SetRenderState( D3DRS_FOGENABLE, FALSE );
m_pD3Ddev->SetRenderState( D3DRS_MULTISAMPLEANTIALIAS, FALSE );
m_pD3Ddev->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
m_pD3Ddev->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE );
m_pD3Ddev->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );
m_pD3Ddev->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );
m_pD3Ddev->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );
m_pD3Ddev->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );
if ( iStateBlock )
m_pD3Ddev->EndStateBlock( &m_pD3DstateDraw );
else
m_pD3Ddev->EndStateBlock( &m_pD3DstateNorm );
}
m_statesOK = true;
return S_OK;
}
HRESULT CD3DBaseRender::DeleteStates ()
{
SAFE_RELEASE( m_pD3DstateDraw );
SAFE_RELEASE( m_pD3DstateNorm );
m_statesOK = false;
return S_OK;
}
CD3DFont::CD3DFont ( const char *szFontName, int fontHeight, DWORD dwCreateFlags )
{
strcpy( m_szFontName, (szFontName ? szFontName : "Arial") );
m_fontHeight = fontHeight;
m_dwCreateFlags = dwCreateFlags;
m_isReady = false;
m_statesOK = false;
m_pD3Dtex = NULL;
m_pD3Dbuf = NULL;
m_pRender = NULL;
m_maxTriangles = 224 * 2;
m_texWidth = m_texHeight = 0;
m_chrSpacing = 0;
memset( m_fTexCoords, 0, sizeof(float) * 224 * 4 );
m_fChrHeight = 0.0;
}
CD3DFont::~CD3DFont ()
{
Invalidate();
}
/* god, what a mess */
HRESULT CD3DFont::Initialize ( IDirect3DDevice9 *pD3Ddev )
{
if ( FAILED(CD3DBaseRender::Initialize(pD3Ddev)) )
return E_FAIL;
if ( m_pRender == NULL && (m_pRender = new CD3DRender(16)) == NULL )
return E_FAIL;
if ( FAILED(m_pRender->Initialize(pD3Ddev)) )
return E_FAIL;
m_texWidth = m_texHeight = 512;
if ( FAILED(m_pD3Ddev->CreateTexture(m_texWidth, m_texHeight, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &m_pD3Dtex,
NULL)) )
return E_FAIL;
if ( FAILED(m_pD3Ddev->CreateVertexBuffer(m_maxTriangles * 3 * sizeof(d3dvertex_s),
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pD3Dbuf, NULL)) )
{
SAFE_RELEASE( m_pD3Dtex );
return E_FAIL;
}
DWORD *pBitmapBits;
BITMAPINFO bmi;
memset( &bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER) );
bmi.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
bmi.bmiHeader.biWidth = m_texWidth;
bmi.bmiHeader.biHeight = -m_texHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biBitCount = 32;
HDC hDC = CreateCompatibleDC( NULL );
HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS, (void **) &pBitmapBits, NULL, 0 );
SetMapMode( hDC, MM_TEXT );
int iHeight = -m_fontHeight * (int)GetDeviceCaps( hDC, LOGPIXELSY ) / 72;
HFONT hFont = CreateFont( iHeight, 0, 0, 0, (m_dwCreateFlags & FCR_BOLD) ? FW_BOLD : FW_NORMAL,
m_dwCreateFlags & FCR_ITALICS, false, false, DEFAULT_CHARSET, OUT_TT_PRECIS,
CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, m_szFontName );
if ( hFont == NULL )
{
DeleteObject( hbmBitmap );
DeleteDC( hDC );
DeleteObject( hFont );
SAFE_RELEASE( m_pD3Dtex );
return E_FAIL;
}
SelectObject( hDC, hbmBitmap );
SelectObject( hDC, hFont );
RECT all = { 0, 0, m_texWidth - 1, m_texWidth - 1 };
HBRUSH green = CreateSolidBrush( RGB(0, 255, 0) );
FillRect( hDC, &all, green );
DeleteObject( green );
SetBkMode( hDC, TRANSPARENT );
SetTextAlign( hDC, TA_TOP );
SIZE size;
char ch = ' ';
GetTextExtentPoint32( hDC, &ch, 1, &size );
m_chrSpacing = ( size.cx + 3 ) / 4;
m_fChrHeight = (float)( size.cy );
if ( m_dwCreateFlags & FCR_BORDER )
{
size.cx += 2;
size.cy += 2;
}
int y = 0, x = ( size.cx + 3 ) / 4;
for ( int c = 32; c < 256; c++ )
{
ch = (char)c;
GetTextExtentPoint32( hDC, &ch, 1, &size );
if ( m_dwCreateFlags & FCR_BORDER )
{
size.cx += 3;
size.cy += 3;
}
if ( x + size.cx + m_chrSpacing > m_texWidth )
{
x = m_chrSpacing;
if ( y + size.cy * 2 + 2 < m_texHeight )
y += size.cy + 1;
}
RECT rect = { x, y, x + size.cx, y + size.cy };
if ( m_dwCreateFlags & FCR_BORDER )
{
// XXX retarded :p use font outline instead
SetTextColor( hDC, RGB(0, 0, 0) );
x++;
y++;
ExtTextOut( hDC, x - 1, y - 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x, y - 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x + 1, y - 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x + 1, y, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x + 1, y + 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x, y + 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x - 1, y + 1, ETO_CLIPPED, &rect, &ch, 1, NULL );
ExtTextOut( hDC, x - 1, y, ETO_CLIPPED, &rect, &ch, 1, NULL );
SetTextColor( hDC, RGB(255, 0, 0) );
ExtTextOut( hDC, x, y, ETO_CLIPPED, &rect, &ch, 1, NULL );
x--;
y--;
}
else
{
SetTextColor( hDC, RGB(255, 0, 0) );
ExtTextOut( hDC, x, y, ETO_CLIPPED, &rect, &ch, 1, NULL );
}
//tu src + dst
m_fTexCoords[c - 32][0] = (float)( x + 0 - m_chrSpacing ) / (float)m_texWidth;
m_fTexCoords[c - 32][2] = (float)( x + size.cx + m_chrSpacing ) / (float)m_texWidth;
//tv src + dst
m_fTexCoords[c - 32][1] = (float)( y + 0 + 0 ) / (float)m_texHeight;
m_fTexCoords[c - 32][3] = (float)( y + size.cy + 0 ) / (float)m_texHeight;
x += size.cx + ( 2 * m_chrSpacing );
}
D3DLOCKED_RECT d3dlr;
m_pD3Dtex->LockRect( 0, &d3dlr, 0, 0 );
BYTE *pDstRow = (BYTE *)d3dlr.pBits;
WORD *pDst16;
for ( y = 0; y < m_texHeight; y++ )
{
pDst16 = (WORD *)pDstRow;
for ( x = 0; x < m_texWidth; x++ )
{
DWORD pixel = pBitmapBits[m_texWidth * y + x];
BYTE bAlpha = 15 - ( ((BYTE) (pixel >> 8)) >> 4 ); // green channel
BYTE bValue = ( (BYTE) (pixel >> 16) ) >> 4; // red channel
*pDst16 = ( WORD ) ( bAlpha << 12 ) | ( bValue << 8 ) | ( bValue << 4 ) | ( bValue );
pDst16++;
}
pDstRow += d3dlr.Pitch;
}
m_pD3Dtex->UnlockRect( 0 );
DeleteObject( hbmBitmap );
DeleteDC( hDC );
DeleteObject( hFont );
m_isReady = true;
return S_OK;
}
HRESULT CD3DFont::Invalidate ()
{
m_isReady = false;
SAFE_RELEASE( m_pD3Dtex );
SAFE_RELEASE( m_pD3Dbuf );
//SAFE_RELEASE(m_pD3DstateDraw);
//SAFE_RELEASE(m_pD3DstateNorm);
m_pRender->Invalidate();
CD3DBaseRender::Invalidate();
return S_OK;
}
HRESULT CD3DFont::Print ( float x, float y, DWORD color, const char *szText, bool textcoloring )
{
if ( !m_isReady )
return E_FAIL;
float strWidth = DrawLength( szText );
x -= (float)m_chrSpacing;
if ( FAILED(this->BeginRender()) )
return E_FAIL;
//
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, false );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, false );
//
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_BITMAPFONT );
m_pD3Ddev->SetTexture( 0, m_pD3Dtex );
m_pD3Ddev->SetStreamSource( 0, m_pD3Dbuf, 0, sizeof(d3dvertex_s) );
DWORD currentcolor = color;
bool GettingColor = false;
while ( *szText )
{
UINT usedTriangles = 0;
d3dvertex_s *pVertex;
if ( FAILED(m_pD3Dbuf->Lock(0, 0, (void **) &pVertex, D3DLOCK_DISCARD)) )
{
m_pD3Ddev->SetFVF( fvf );
this->EndRender();
return E_FAIL;
}
for ( ; *szText; szText++ )
{
if(textcoloring)
{
if(*szText == '{')
{
char ccolor[9] = {0};
unsigned long tempcolor = 0;
for(unsigned int i = 1; i < 10; ++i)
{
if(*(szText+i))
{
if(i == 9)
{
if(*(szText+(i)) != '}')
{
break;
}
if(sscanf(ccolor, "%x", &tempcolor) != 1)
{
break;
}
currentcolor = tempcolor;
szText+=9;
GettingColor = true;
break;
}
ccolor[i-1] = *(szText+i);
}
else
{
break;
}
}
}
}
if(GettingColor)
{
GettingColor = false;
continue;
}
int c = *(unsigned char *)szText - 32;
if ( !(c >= 0 && c < 224) )
continue;
float tx1 = m_fTexCoords[c][0];
float tx2 = m_fTexCoords[c][2];
float ty1 = m_fTexCoords[c][1];
float ty2 = m_fTexCoords[c][3];
float w = ( tx2 - tx1 ) * m_texWidth;
float h = ( ty2 - ty1 ) * m_texHeight;
*pVertex++ = Init2DVertex( x - 0.5f, y - 0.5f, currentcolor, tx1, ty1 ); //topleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, currentcolor, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, currentcolor, tx1, ty2 ); //bottomleft
*pVertex++ = Init2DVertex( x + w - 0.5f, y - 0.5f, currentcolor, tx2, ty1 ); //topright
*pVertex++ = Init2DVertex( x + w - 0.5f, y + h - 0.5f, currentcolor, tx2, ty2 ); //bottomright
*pVertex++ = Init2DVertex( x - 0.5f, y + h - 0.5f, currentcolor, tx1, ty2 ); //bottomleft
if ( m_dwCreateFlags & FCR_BORDER )
w -= 2.0f;
x += w - ( m_chrSpacing * 2 );
usedTriangles += 2;
if ( usedTriangles >= m_maxTriangles )
break;
}
if ( usedTriangles > 0 )
{
m_pD3Dbuf->Unlock();
m_pD3Ddev->DrawPrimitive( D3DPT_TRIANGLELIST, 0, usedTriangles );
}
}
m_pD3Ddev->SetFVF( fvf );
//
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, true );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, true );
//
this->EndRender();
return S_OK;
}
HRESULT CD3DFont::PrintShadow ( float x, float y, DWORD color, const char *szText )
{
Print( x, y, color, szText );
return S_OK;
}
float CD3DFont::DrawLength ( const char *szText ) const
{
float len = 0.0f;
float sub = ( m_dwCreateFlags & FCR_BORDER ) ? 2.0f : 0.0f;
for ( const char *p = szText; *p; p++ )
{
int c = *(unsigned char *)p - 32;
if ( c >= 0 && c < 224 )
len += ( (m_fTexCoords[c][2] - m_fTexCoords[c][0]) * m_texWidth - sub ) - m_chrSpacing * 2;
}
return len;
}
CD3DRender::CD3DRender ( int numVertices )
{
m_canRender = false;
m_pD3Dbuf = NULL;
m_pVertex = NULL;
m_color = 0;
m_tu = 0.0f;
m_tv = 0.0f;
m_texture = NULL;
m_maxVertex = numVertices;
m_curVertex = 0;
}
CD3DRender::~CD3DRender ()
{
Invalidate();
}
HRESULT CD3DRender::Initialize ( IDirect3DDevice9 *pD3Ddev )
{
if ( !m_canRender )
{
if ( FAILED(CD3DBaseRender::Initialize(pD3Ddev)) )
return E_FAIL;
if ( FAILED(m_pD3Ddev->CreateVertexBuffer(m_maxVertex * sizeof(d3dvertex_s),
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pD3Dbuf, NULL)) )
return E_FAIL;
m_canRender = true;
}
return S_OK;
}
HRESULT CD3DRender::Invalidate ()
{
SAFE_RELEASE( m_pD3Dbuf );
SAFE_RELEASE( m_texture );
//m_pVertex = NULL;
//SAFE_RELEASE(m_pD3DstateDraw);
//SAFE_RELEASE(m_pD3DstateNorm);
//CD3DBaseRender::Invalidate();
//m_canRender = false;
return S_OK;
}
HRESULT CD3DRender::Begin ( D3DPRIMITIVETYPE primType )
{
if ( !m_canRender )
return E_FAIL;
if ( m_pVertex != NULL )
return E_FAIL;
if ( FAILED(m_pD3Dbuf->Lock(0, 0, (void **) &m_pVertex, D3DLOCK_DISCARD)) )
return E_FAIL;
m_primType = primType;
return S_OK;
}
HRESULT CD3DRender::End ()
{
int numPrims;
m_pVertex = NULL;
if ( !m_canRender )
{
m_curVertex = 0;
return E_FAIL;
}
if ( FAILED(CD3DBaseRender::BeginRender()) )
return E_FAIL;
switch ( m_primType )
{
case D3DPT_POINTLIST:
numPrims = m_curVertex;
break;
case D3DPT_LINELIST:
numPrims = m_curVertex / 2;
break;
case D3DPT_LINESTRIP:
numPrims = m_curVertex - 1;
break;
case D3DPT_TRIANGLELIST:
numPrims = m_curVertex / 3;
break;
case D3DPT_TRIANGLESTRIP:
case D3DPT_TRIANGLEFAN:
numPrims = m_curVertex - 2;
break;
default:
numPrims = 0;
break;
}
m_curVertex = 0;
if ( numPrims > 0 )
{
m_pD3Dbuf->Unlock();
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
if ( m_texture == NULL )
{
m_pD3Ddev->SetFVF( D3DFVF_PRIMITIVES );
m_pD3Ddev->SetTexture( 0, NULL );
}
else
{
m_pD3Ddev->SetFVF( D3DFVF_BITMAPFONT );
m_pD3Ddev->SetTexture( 0, m_texture );
}
m_pD3Ddev->SetStreamSource( 0, m_pD3Dbuf, 0, sizeof(d3dvertex_s) );
m_pD3Ddev->DrawPrimitive( m_primType, 0, numPrims );
m_pD3Ddev->SetFVF( fvf );
}
CD3DBaseRender::EndRender();
return S_OK;
}
HRESULT CD3DRender::D3DColor ( DWORD color )
{
m_color = color;
return m_canRender ? S_OK : E_FAIL;
return S_OK;
}
void CD3DRender::D3DBindTexture ( IDirect3DTexture9 *texture )
{
m_texture = texture;
}
void CD3DRender::D3DTexCoord2f ( float u, float v )
{
m_tu = u;
m_tv = v;
}
HRESULT CD3DRender::D3DVertex2f ( float x, float y )
{
if ( m_canRender && m_pVertex && ++m_curVertex < m_maxVertex )
*m_pVertex++ = Init2DVertex( x, y, m_color, m_tu, m_tv );
else
return E_FAIL;
return S_OK;
}
void CD3DRender::D3DTexQuad ( float sx, float sy, float ex, float ey, float su, float sv, float eu, float ev )
{
if ( SUCCEEDED(Begin(D3DPT_TRIANGLELIST)) )
{
D3DColor( D3DCOLOR_XRGB(255, 255, 255) );
D3DTexCoord2f( su, sv );
D3DVertex2f( sx, sy );
D3DTexCoord2f( eu, sv );
D3DVertex2f( ex, sy );
D3DTexCoord2f( su, ev );
D3DVertex2f( sx, ey );
D3DTexCoord2f( su, ev );
D3DVertex2f( sx, ey );
D3DTexCoord2f( eu, sv );
D3DVertex2f( ex, sy );
D3DTexCoord2f( eu, ev );
D3DVertex2f( ex, ey );
End();
}
}
void CD3DRender::D3DBox ( float x, float y, float w, float h, D3DCOLOR color )
{
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, false );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, false );
if ( SUCCEEDED(Begin(D3DPT_TRIANGLELIST)) )
{
D3DColor( color );
D3DVertex2f( x, y );
D3DVertex2f( x + w, y );
D3DVertex2f( x, y + h );
D3DVertex2f( x, y + h );
D3DVertex2f( x + w, y );
D3DVertex2f( x + w, y + h );
End();
}
// reset states
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, true );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, true );
}
void CD3DRender::D3DBoxi ( int x, int y, int w, int h, D3DCOLOR color, int maxW )
{
if ( maxW )
{
if ( w >= maxW )
( w = maxW );
D3DBox( (float)x, (float)y, (float)w, (float)h, color );
}
else
{
D3DBox( (float)x, (float)y, (float)w, (float)h, color );
}
}
void CD3DRender::D3DBoxBorder ( float x, float y, float w, float h, D3DCOLOR border_color, D3DCOLOR color )
{
D3DBox( x, y, w, 1.0f, border_color );
D3DBox( x + w, y, 1.0f, h, border_color );
D3DBox( x, y, 1.0f, h, border_color );
D3DBox( x, y + h, w, 1.0f, border_color );
D3DBox( x + 1.0f, y + 1.0f, w - 1.0f, h - 1.0f, color );
}
void CD3DRender::D3DBoxBorderi ( int x, int y, int w, int h, D3DCOLOR border_color, D3DCOLOR color )
{
D3DBoxBorder( (float)x, (float)y, (float)w, (float)h, border_color, color );
}
bool CD3DRender::DrawLine ( const D3DXVECTOR3 &a, const D3DXVECTOR3 &b, DWORD dwColor )
{
if ( FAILED(CD3DBaseRender::BeginRender()) )
return false;
////////////////////////////////////////////////////
// Make sure we have a valid vertex buffer.
if ( m_pD3Dbuf == NULL )
{
return false;
}
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
//m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, false );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, false );
//m_pD3Ddev->SetRenderState ( D3DRS_LIGHTING, false );
D3DLVERTEX lineList[2];
//////////////////////////////////////////////////
// Lock the vertex buffer and copy in the verts.
m_pD3Dbuf->Lock( 0, 0, (void **) &lineList, D3DLOCK_DISCARD | D3DLOCK_NOSYSLOCK ); // flogs: D3DLOCK_NOSYSLOCK, D3DLOCK_DISCARD
{
lineList[0].x = a.x;
lineList[0].y = a.y;
lineList[0].z = a.z;
lineList[0].color = dwColor;
lineList[0].specular = dwColor;
lineList[1].x = b.x;
lineList[1].y = b.y;
lineList[1].z = b.z;
lineList[1].color = dwColor;
lineList[1].specular = dwColor;
}
m_pD3Dbuf->Unlock();
// store FVF to restore original at the end of this function
DWORD fvf;
m_pD3Ddev->GetFVF( &fvf );
m_pD3Ddev->SetFVF( D3DFVF_LVERTEX );
//m_pD3Ddev->SetFVF( D3DFVF_PRIMITIVES );
////////////////////////////////////////////////////
// Draw!
m_pD3Ddev->DrawPrimitiveUP( D3DPT_LINESTRIP, 1, lineList, sizeof(lineList) / 2 );
// reset states
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pD3Ddev->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
m_pD3Ddev->SetRenderState ( D3DRS_ZENABLE, true );
m_pD3Ddev->SetRenderState( D3DRS_CLIPPING, true );
// restore FVF
m_pD3Ddev->SetFVF( fvf );
CD3DBaseRender::EndRender();
return true;
}
Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIFRoaXMgZm9udCBjbGFzcyB3YXMgY3JlYXRlZCBieSBBem9yYml4IChNYXR0aGV3IEwpIGZvciBHYW1lLURlY2VwdGlvbgovLyBodHRwOi8vdy4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ubi5jb20gICBodHRwOi8vZi4uLmNvbnRlbnQtYXZhaWxhYmxlLXRvLWF1dGhvci1vbmx5Li4ubi5jb20KLy8gaXJjOi8vaXJjLnJpem9uLm5ldC9nYW1lLWRlY2VwdGlvbgovLwovLyBBIGxvdCBhbGwgb2YgdGhlIENEM0RGb250OjpJbml0aWFsaXplKCkgY29kZSB3YXMgY3JlYXRlZCBieSBNaWNyb3NvZnQKLy8gKHRha2VuIGZyb20gdGhlIEQzRDkgU0RLKQovLwovLyBQbGVhc2Ugbm90ZSB0aGF0IHRoaXMgaXMgTk9UIDEwMCUgY29tcGxldGUgeWV0LCBjb2xvdXIgdGFncyBhbmQKLy8gc2hhZG93cyBhcmUgbm90IGltcGxlbWVudGVkIHlldAovLwovLyBVU0FHRToKLy8gICBDRDNERm9udDoKLy8gICAgIDEpIEluc3RhbmNpYXRlIHRoZSBjbGFzcyB3aXRoIHRoZSBwYXJhbWV0ZXJpemVkIGNvbnN0cnVjdG9yCi8vICAgICAgICBlZyBDRDNERm9udCAqZ19wRDNEZm9udCA9IG5ldyBDRDNERm9udCgiQXJpYWwiLCAxNiwgRkNUX0JPTEQpOwovLwovLyAgICAgMikgQ2FsbCBJbml0aWFsaXplKCkgYWZ0ZXIgb3RoZXIgcmVuZGVyaW5nIGlzIHJlYWR5Ci8vICAgICAgICBlZyBnX3BEM0RGb250LT5Jbml0aWFsaXplKHBEM0RkZXZpY2UpOwovLwovLyAgICAgMykgVG8gYmVnaW4gcmVuZGVyaW5nIHVzZSBQcmludCBmdW5jdGlvbgovLyAgICAgICAgZWcgZ19wRDNERm9udC0+UHJpbnQoMTAuMGYsIDUwLjBmLCAweEZGMDBGRjAwLCAiSGVsbG8gV29ybGQiLCBGVF9CT1JERVIpOwovLwovLyAgICAgNCkgY2FsbCBJbnZhbGlkYXRlKCkgdXBvbiBSZXNldCBvZiB0aGUgRDNEIHN1cmZhY2UgYW5kIHJlLWluaXRpYWxpemUKLy8KLy8gICBDRDNEUmVuZGVyOgovLyAgICAgMSkgSW5zdGFuY2lhdGUgdGhlIGNsYXNzIHdpdGggdGhlIHBhcmFtZXRlcml6ZWQgY29uc3RydWN0b3IKLy8gICAgICAgIGVnIENEM0RSZW5kZXIgKmdfcFJlbmRlciA9IG5ldyBDRDNEUmVuZGVyKDEyOCk7Ci8vCi8vICAgICAyKSBDYWxsIEluaXRpYWxpemUoKSBhZnRlciBvdGhlciByZW5kZXJpbmcgaXMgcmVhZHkKLy8gICAgICAgIGVnIGdfcFJlbmRlci0+SW5pdGlhbGl6ZShwRDNEZGV2aWNlKTsKLy8KLy8gICAgIDMpIFRvIGJlZ2luIHJlbmRlcmluZywgc3RhcnQgcmVuZGVyaW5nIG11Y2ggbGlrZSBPcGVuR0wKLy8gICAgICAgIGVnIGlmKCBTVUNDRUVERUQoZ19wUmVuZGVyLT5CZWdpbihEM0RQVF9UUklBTkdMRUxJU1QpKSApCi8vICAgICAgICAgICB7Ci8vICAgICAgICAgICAgICAgRDNEQWRkUXVhZChnX3BSZW5kZXIsIDEwLjBmLCAxMC4wZiwgNTAuMGYsIDUwLjBmLCAweEZGRkYwMDAwKTsgLy9oZWxwZXIgZnVuY3Rpb24KLy8gICAgICAgICAgICAgICBnX3BSZW5kZXItPkQzRENvbG91cigweEZGMDAwMEZGKTsgLy9ibHVlCi8vICAgICAgICAgICAgICAgZ19wUmVuZGVyLT5EM0RWZXJ0ZXgyZig2MC4wZiwgNjAuMGYpOwovLyAgICAgICAgICAgICAgIGdfcFJlbmRlci0+RDNEVmVydGV4MmYoNjAuMGYsIDExMC4wZik7Ci8vICAgICAgICAgICAgICAgZ19wUmVuZGVyLT5EM0RWZXJ0ZXgyZigxMTAuMGYsIDExMC4wZik7Ci8vICAgICAgICAgICAgICAgZ19wUmVuZGVyLT5FbmQoKTsKLy8gICAgICAgICAgIH0KLy8KLy8gICAgIDQpIGNhbGwgSW52YWxpZGF0ZSgpIHVwb24gUmVzZXQgb2YgdGhlIEQzRCBzdXJmYWNlIGFuZCByZS1pbml0aWFsaXplCi8vCi8vIEZBU1RFUiBSRU5ERVJJTkcgKEFkdmFuY2VkIGJ1dCBOT1QgUkVRVUlSRUQpOgovLyAgIFRvIGVuYWJsZSBmYXN0ZXIgcmVuZGVyaW5nLCBpdCdzIGlkZWFsIHRvIGNhbGwgc3RhdGljIGZ1bmN0aW9uIENEM0RCYXNlUmVuZGVyaW5nOjpCZWdpblJlbmRlcigpOyBiZWZvcmUKLy8gICBvdGhlciBmb250IC8gcHJpbWl0aXZlIHJlbmRlcmluZyBjb2RlLCBhbmQgY2FsbCBDRDNEQmFzZVJlbmRlcmluZzo6RW5kUmVuZGVyKCk7IGFmdGVyd2FyZHMKLy8gICAqKiogSVQgSVMgQ1JVQ0lBTCBUSEFUIFlPVSBDQUxMIEVuZFJlbmRlciBGT1IgRVZFUlkgQmVnaW5SZW5kZXIoKSBDQUxMICoqKgovLyAgICoqKiBJTUFHRSBSRU5ERVJJTkcgTUFZIEJFQ09NRSBDT1JSVVBUIElGIFlPVSBETyBOT1QgKioqCi8vICAgZWcKLy8gICAgIGlmKCBTVUNDRUVERUQoQ0QzREJhc2VSZW5kZXI6OkJlZ2luUmVuZGVyKCkpICkKLy8gICAgIHsKLy8gICAgICAgICAvL3ByaW1pdGl2ZSBhbmQgZm9udCByZW5kZXJpbmcgZ29lcyBoZXJlCi8vICAgICAgICAgQ0QzREJhc2VSZW5kZXI6OkVuZFJlbmRlcigpOwovLyAgICAgfQovLwojaW5jbHVkZSAibWFpbi5oIgojaW5jbHVkZSAiY2QzZGZvbnQuaCIKCklEaXJlY3QzRERldmljZTkgKkNEM0RCYXNlUmVuZGVyOjogICAgCW1fcEQzRGRldiA9IE5VTEw7CklEaXJlY3QzRFN0YXRlQmxvY2s5ICpDRDNEQmFzZVJlbmRlcjo6CW1fcEQzRHN0YXRlRHJhdyA9IE5VTEw7CklEaXJlY3QzRFN0YXRlQmxvY2s5ICpDRDNEQmFzZVJlbmRlcjo6CW1fcEQzRHN0YXRlTm9ybSA9IE5VTEw7CmludCBDRDNEQmFzZVJlbmRlcjo6CQkJCQltX3JlbmRlckNvdW50ID0gMDsKaW50IENEM0RCYXNlUmVuZGVyOjoJCQkJCW1fbnVtU2hhcmVkID0gMDsKYm9vbCBDRDNEQmFzZVJlbmRlcjo6CQkJCQltX3N0YXRlc09LID0gZmFsc2U7CgppbmxpbmUgZDNkdmVydGV4X3MgSW5pdDJEVmVydGV4ICggZmxvYXQgeCwgZmxvYXQgeSwgRFdPUkQgY29sb3IsIGZsb2F0IHR1LCBmbG9hdCB0diApCnsKCWQzZHZlcnRleF9zIHYgPSB7IHgsIHksIDEuMGYsIDEuMGYsIGNvbG9yLCB0dSwgdHYgfTsKCXJldHVybiB2Owp9CgpDRDNEQmFzZVJlbmRlcjo6Q0QzREJhc2VSZW5kZXIgKCkKewoJbV9udW1TaGFyZWQrKzsKfQoKQ0QzREJhc2VSZW5kZXI6On5DRDNEQmFzZVJlbmRlciAoKQp7CglpZiAoIC0tbV9udW1TaGFyZWQgPT0gMCApCgkJRGVsZXRlU3RhdGVzKCk7Cn0KCkhSRVNVTFQgQ0QzREJhc2VSZW5kZXI6OkluaXRpYWxpemUgKCBJRGlyZWN0M0REZXZpY2U5ICpwRDNEZGV2ICkKewoJaWYgKCBtX3BEM0RkZXYgPT0gTlVMTCAmJiAobV9wRDNEZGV2ID0gcEQzRGRldikgPT0gTlVMTCApCgkJcmV0dXJuIEVfRkFJTDsKCglpZiAoICFtX3N0YXRlc09LICYmIEZBSUxFRChDcmVhdGVTdGF0ZXMoKSkgKQoJCXJldHVybiBFX0ZBSUw7CgoJcmV0dXJuIFNfT0s7Cn0KCkhSRVNVTFQgQ0QzREJhc2VSZW5kZXI6OkludmFsaWRhdGUgKCkKewoJRGVsZXRlU3RhdGVzKCk7CglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNEQmFzZVJlbmRlcjo6QmVnaW5SZW5kZXIgKCkKewoJaWYgKCAhbV9zdGF0ZXNPSyApCgkJcmV0dXJuIEVfRkFJTDsKCWlmICggKyttX3JlbmRlckNvdW50ID09IDEgKQoJewoJCV9fdHJ5CgkJewoJCQltX3BEM0RzdGF0ZU5vcm0tPkNhcHR1cmUoKTsKCQl9CgkJX19leGNlcHQoRVhDRVBUSU9OX0VYRUNVVEVfSEFORExFUikKCQl7CgkJCS0tbV9yZW5kZXJDb3VudDsKCQkJcmV0dXJuIEVfRkFJTDsKCQl9CgkJbV9wRDNEc3RhdGVEcmF3LT5BcHBseSgpOwoJfQoJcmV0dXJuIFNfT0s7Cn0KCkhSRVNVTFQgQ0QzREJhc2VSZW5kZXI6OkVuZFJlbmRlciAoKQp7CglpZiAoICFtX3N0YXRlc09LICkKCQlyZXR1cm4gRV9GQUlMOwoKCW1fcmVuZGVyQ291bnQtLTsKCglpZiAoIG1fcmVuZGVyQ291bnQgPT0gMCApCgkJbV9wRDNEc3RhdGVOb3JtLT5BcHBseSgpOwoJZWxzZSBpZiAoIG1fcmVuZGVyQ291bnQgPCAwICkKCQltX3JlbmRlckNvdW50ID0gMDsKCglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNEQmFzZVJlbmRlcjo6Q3JlYXRlU3RhdGVzICgpCnsKCWZvciAoIGludCBpU3RhdGVCbG9jayA9IDA7IGlTdGF0ZUJsb2NrIDwgMjsgaVN0YXRlQmxvY2srKyApCgl7CgkJbV9wRDNEZGV2LT5CZWdpblN0YXRlQmxvY2soKTsKCQltX3BEM0RkZXYtPlNldFBpeGVsU2hhZGVyKCBOVUxMICk7CgkJbV9wRDNEZGV2LT5TZXRWZXJ0ZXhTaGFkZXIoIE5VTEwgKTsKCgkJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfQUxQSEFCTEVOREVOQUJMRSwgVFJVRSApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX1NSQ0JMRU5ELCBEM0RCTEVORF9TUkNBTFBIQSApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0RFU1RCTEVORCwgRDNEQkxFTkRfSU5WU1JDQUxQSEEgKTsKCQltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19BTFBIQVRFU1RFTkFCTEUsIFRSVUUgKTsKCQltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19BTFBIQVJFRiwgMHgwOCApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0FMUEhBRlVOQywgRDNEQ01QX0dSRUFURVJFUVVBTCApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0ZJTExNT0RFLCBEM0RGSUxMX1NPTElEICk7CgkJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfQ1VMTE1PREUsIEQzRENVTExfQ0NXICk7CgkJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfU1RFTkNJTEVOQUJMRSwgRkFMU0UgKTsKCQltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19DTElQUElORywgVFJVRSApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0NMSVBQTEFORUVOQUJMRSwgRkFMU0UgKTsKCQltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19WRVJURVhCTEVORCwgRDNEVkJGX0RJU0FCTEUgKTsKCQltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19JTkRFWEVEVkVSVEVYQkxFTkRFTkFCTEUsIEZBTFNFICk7CgkJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfRk9HRU5BQkxFLCBGQUxTRSApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX01VTFRJU0FNUExFQU5USUFMSUFTLCBGQUxTRSApOwoJCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0NPTE9SV1JJVEVFTkFCTEUsIEQzRENPTE9SV1JJVEVFTkFCTEVfUkVEIHwgRDNEQ09MT1JXUklURUVOQUJMRV9HUkVFTiB8CgkJCQkJCQkJICAgRDNEQ09MT1JXUklURUVOQUJMRV9CTFVFIHwgRDNEQ09MT1JXUklURUVOQUJMRV9BTFBIQSApOwoKCQltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQ09MT1JPUCwgRDNEVE9QX01PRFVMQVRFICk7CgkJbV9wRDNEZGV2LT5TZXRUZXh0dXJlU3RhZ2VTdGF0ZSggMCwgRDNEVFNTX0NPTE9SQVJHMSwgRDNEVEFfVEVYVFVSRSApOwoJCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19DT0xPUkFSRzIsIEQzRFRBX0RJRkZVU0UgKTsKCQltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQUxQSEFPUCwgRDNEVE9QX01PRFVMQVRFICk7CgkJbV9wRDNEZGV2LT5TZXRUZXh0dXJlU3RhZ2VTdGF0ZSggMCwgRDNEVFNTX0FMUEhBQVJHMSwgRDNEVEFfVEVYVFVSRSApOwoJCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19BTFBIQUFSRzIsIEQzRFRBX0RJRkZVU0UgKTsKCQltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfVEVYQ09PUkRJTkRFWCwgMCApOwoJCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19URVhUVVJFVFJBTlNGT1JNRkxBR1MsIEQzRFRURkZfRElTQUJMRSApOwoJCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDEsIEQzRFRTU19DT0xPUk9QLCBEM0RUT1BfRElTQUJMRSApOwoJCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDEsIEQzRFRTU19BTFBIQU9QLCBEM0RUT1BfRElTQUJMRSApOwoKCQltX3BEM0RkZXYtPlNldFNhbXBsZXJTdGF0ZSggMCwgRDNEU0FNUF9NSU5GSUxURVIsIEQzRFRFWEZfUE9JTlQgKTsKCQltX3BEM0RkZXYtPlNldFNhbXBsZXJTdGF0ZSggMCwgRDNEU0FNUF9NQUdGSUxURVIsIEQzRFRFWEZfUE9JTlQgKTsKCQltX3BEM0RkZXYtPlNldFNhbXBsZXJTdGF0ZSggMCwgRDNEU0FNUF9NSVBGSUxURVIsIEQzRFRFWEZfTk9ORSApOwoKCQlpZiAoIGlTdGF0ZUJsb2NrICkKCQkJbV9wRDNEZGV2LT5FbmRTdGF0ZUJsb2NrKCAmbV9wRDNEc3RhdGVEcmF3ICk7CgkJZWxzZQoJCQltX3BEM0RkZXYtPkVuZFN0YXRlQmxvY2soICZtX3BEM0RzdGF0ZU5vcm0gKTsKCX0KCgltX3N0YXRlc09LID0gdHJ1ZTsKCglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNEQmFzZVJlbmRlcjo6RGVsZXRlU3RhdGVzICgpCnsKCVNBRkVfUkVMRUFTRSggbV9wRDNEc3RhdGVEcmF3ICk7CglTQUZFX1JFTEVBU0UoIG1fcEQzRHN0YXRlTm9ybSApOwoJbV9zdGF0ZXNPSyA9IGZhbHNlOwoKCXJldHVybiBTX09LOwp9CgpDRDNERm9udDo6Q0QzREZvbnQgKCBjb25zdCBjaGFyICpzekZvbnROYW1lLCBpbnQgZm9udEhlaWdodCwgRFdPUkQgZHdDcmVhdGVGbGFncyApCnsKCXN0cmNweSggbV9zekZvbnROYW1lLCAoc3pGb250TmFtZSA/IHN6Rm9udE5hbWUgOiAiQXJpYWwiKSApOwoKCW1fZm9udEhlaWdodCA9IGZvbnRIZWlnaHQ7CgltX2R3Q3JlYXRlRmxhZ3MgPSBkd0NyZWF0ZUZsYWdzOwoKCW1faXNSZWFkeSA9IGZhbHNlOwoJbV9zdGF0ZXNPSyA9IGZhbHNlOwoKCW1fcEQzRHRleCA9IE5VTEw7CgltX3BEM0RidWYgPSBOVUxMOwoJbV9wUmVuZGVyID0gTlVMTDsKCgltX21heFRyaWFuZ2xlcyA9IDIyNCAqIDI7CgoJbV90ZXhXaWR0aCA9IG1fdGV4SGVpZ2h0ID0gMDsKCW1fY2hyU3BhY2luZyA9IDA7CgoJbWVtc2V0KCBtX2ZUZXhDb29yZHMsIDAsIHNpemVvZihmbG9hdCkgKiAyMjQgKiA0ICk7CgoJbV9mQ2hySGVpZ2h0ID0gMC4wOwp9CgpDRDNERm9udDo6fkNEM0RGb250ICgpCnsKCUludmFsaWRhdGUoKTsKfQoKLyogZ29kLCB3aGF0IGEgbWVzcyAqLwpIUkVTVUxUIENEM0RGb250OjpJbml0aWFsaXplICggSURpcmVjdDNERGV2aWNlOSAqcEQzRGRldiApCnsKCWlmICggRkFJTEVEKENEM0RCYXNlUmVuZGVyOjpJbml0aWFsaXplKHBEM0RkZXYpKSApCgkJcmV0dXJuIEVfRkFJTDsKCglpZiAoIG1fcFJlbmRlciA9PSBOVUxMICYmIChtX3BSZW5kZXIgPSBuZXcgQ0QzRFJlbmRlcigxNikpID09IE5VTEwgKQoJCXJldHVybiBFX0ZBSUw7CgoJaWYgKCBGQUlMRUQobV9wUmVuZGVyLT5Jbml0aWFsaXplKHBEM0RkZXYpKSApCgkJcmV0dXJuIEVfRkFJTDsKCgltX3RleFdpZHRoID0gbV90ZXhIZWlnaHQgPSA1MTI7CgoJaWYgKCBGQUlMRUQobV9wRDNEZGV2LT5DcmVhdGVUZXh0dXJlKG1fdGV4V2lkdGgsIG1fdGV4SGVpZ2h0LCAxLCAwLCBEM0RGTVRfQTRSNEc0QjQsIEQzRFBPT0xfTUFOQUdFRCwgJm1fcEQzRHRleCwKCQkJCSBOVUxMKSkgKQoJCXJldHVybiBFX0ZBSUw7CgoJaWYgKCBGQUlMRUQobV9wRDNEZGV2LT5DcmVhdGVWZXJ0ZXhCdWZmZXIobV9tYXhUcmlhbmdsZXMgKiAzICogc2l6ZW9mKGQzZHZlcnRleF9zKSwKCQkJCSBEM0RVU0FHRV9XUklURU9OTFkgfCBEM0RVU0FHRV9EWU5BTUlDLCAwLCBEM0RQT09MX0RFRkFVTFQsICZtX3BEM0RidWYsIE5VTEwpKSApCgl7CgkJU0FGRV9SRUxFQVNFKCBtX3BEM0R0ZXggKTsKCQlyZXR1cm4gRV9GQUlMOwoJfQoKCURXT1JECQkqcEJpdG1hcEJpdHM7CglCSVRNQVBJTkZPCWJtaTsKCgltZW1zZXQoICZibWkuYm1pSGVhZGVyLCAwLCBzaXplb2YoQklUTUFQSU5GT0hFQURFUikgKTsKCWJtaS5ibWlIZWFkZXIuYmlTaXplID0gc2l6ZW9mKCBCSVRNQVBJTkZPSEVBREVSICk7CglibWkuYm1pSGVhZGVyLmJpV2lkdGggPSBtX3RleFdpZHRoOwoJYm1pLmJtaUhlYWRlci5iaUhlaWdodCA9IC1tX3RleEhlaWdodDsKCWJtaS5ibWlIZWFkZXIuYmlQbGFuZXMgPSAxOwoJYm1pLmJtaUhlYWRlci5iaUNvbXByZXNzaW9uID0gQklfUkdCOwoJYm1pLmJtaUhlYWRlci5iaUJpdENvdW50ID0gMzI7CgoJSERDCQloREMgPSBDcmVhdGVDb21wYXRpYmxlREMoIE5VTEwgKTsKCUhCSVRNQVAgaGJtQml0bWFwID0gQ3JlYXRlRElCU2VjdGlvbiggaERDLCAmYm1pLCBESUJfUkdCX0NPTE9SUywgKHZvaWQgKiopICZwQml0bWFwQml0cywgTlVMTCwgMCApOwoJU2V0TWFwTW9kZSggaERDLCBNTV9URVhUICk7CgoJaW50CQlpSGVpZ2h0ID0gLW1fZm9udEhlaWdodCAqIChpbnQpR2V0RGV2aWNlQ2FwcyggaERDLCBMT0dQSVhFTFNZICkgLyA3MjsKCglIRk9OVAloRm9udCA9IENyZWF0ZUZvbnQoIGlIZWlnaHQsIDAsIDAsIDAsIChtX2R3Q3JlYXRlRmxhZ3MgJiBGQ1JfQk9MRCkgPyBGV19CT0xEIDogRldfTk9STUFMLAoJCQkJCQkJCW1fZHdDcmVhdGVGbGFncyAmIEZDUl9JVEFMSUNTLCBmYWxzZSwgZmFsc2UsIERFRkFVTFRfQ0hBUlNFVCwgT1VUX1RUX1BSRUNJUywKCQkJCQkJCQlDTElQX0RFRkFVTFRfUFJFQ0lTLCBQUk9PRl9RVUFMSVRZLCBWQVJJQUJMRV9QSVRDSCwgbV9zekZvbnROYW1lICk7CgoJaWYgKCBoRm9udCA9PSBOVUxMICkKCXsKCQlEZWxldGVPYmplY3QoIGhibUJpdG1hcCApOwoJCURlbGV0ZURDKCBoREMgKTsKCQlEZWxldGVPYmplY3QoIGhGb250ICk7CgkJU0FGRV9SRUxFQVNFKCBtX3BEM0R0ZXggKTsKCQlyZXR1cm4gRV9GQUlMOwoJfQoKCVNlbGVjdE9iamVjdCggaERDLCBoYm1CaXRtYXAgKTsKCVNlbGVjdE9iamVjdCggaERDLCBoRm9udCApOwoKCVJFQ1QJYWxsID0geyAwLCAwLCBtX3RleFdpZHRoIC0gMSwgbV90ZXhXaWR0aCAtIDEgfTsKCUhCUlVTSAlncmVlbiA9IENyZWF0ZVNvbGlkQnJ1c2goIFJHQigwLCAyNTUsIDApICk7CglGaWxsUmVjdCggaERDLCAmYWxsLCBncmVlbiApOwoJRGVsZXRlT2JqZWN0KCBncmVlbiApOwoKCVNldEJrTW9kZSggaERDLCBUUkFOU1BBUkVOVCApOwoJU2V0VGV4dEFsaWduKCBoREMsIFRBX1RPUCApOwoKCVNJWkUJc2l6ZTsKCWNoYXIJY2ggPSAnICc7CgoJR2V0VGV4dEV4dGVudFBvaW50MzIoIGhEQywgJmNoLCAxLCAmc2l6ZSApOwoKCW1fY2hyU3BhY2luZyA9ICggc2l6ZS5jeCArIDMgKSAvIDQ7CgltX2ZDaHJIZWlnaHQgPSAoZmxvYXQpKCBzaXplLmN5ICk7CgoJaWYgKCBtX2R3Q3JlYXRlRmxhZ3MgJiBGQ1JfQk9SREVSICkKCXsKCQlzaXplLmN4ICs9IDI7CgkJc2l6ZS5jeSArPSAyOwoJfQoKCWludCB5ID0gMCwgeCA9ICggc2l6ZS5jeCArIDMgKSAvIDQ7CgoJZm9yICggaW50IGMgPSAzMjsgYyA8IDI1NjsgYysrICkKCXsKCQljaCA9IChjaGFyKWM7CgoJCUdldFRleHRFeHRlbnRQb2ludDMyKCBoREMsICZjaCwgMSwgJnNpemUgKTsKCQlpZiAoIG1fZHdDcmVhdGVGbGFncyAmIEZDUl9CT1JERVIgKQoJCXsKCQkJc2l6ZS5jeCArPSAzOwoJCQlzaXplLmN5ICs9IDM7CgkJfQoKCQlpZiAoIHggKyBzaXplLmN4ICsgbV9jaHJTcGFjaW5nID4gbV90ZXhXaWR0aCApCgkJewoJCQl4ID0gbV9jaHJTcGFjaW5nOwoJCQlpZiAoIHkgKyBzaXplLmN5ICogMiArIDIgPCBtX3RleEhlaWdodCApCgkJCQl5ICs9IHNpemUuY3kgKyAxOwoJCX0KCgkJUkVDVAlyZWN0ID0geyB4LCB5LCB4ICsgc2l6ZS5jeCwgeSArIHNpemUuY3kgfTsKCgkJaWYgKCBtX2R3Q3JlYXRlRmxhZ3MgJiBGQ1JfQk9SREVSICkKCQl7CgkJCS8vIFhYWCByZXRhcmRlZCA6cCB1c2UgZm9udCBvdXRsaW5lIGluc3RlYWQKCQkJU2V0VGV4dENvbG9yKCBoREMsIFJHQigwLCAwLCAwKSApOwoJCQl4Kys7CgkJCXkrKzsKCQkJRXh0VGV4dE91dCggaERDLCB4IC0gMSwgeSAtIDEsIEVUT19DTElQUEVELCAmcmVjdCwgJmNoLCAxLCBOVUxMICk7CgkJCUV4dFRleHRPdXQoIGhEQywgeCwgeSAtIDEsIEVUT19DTElQUEVELCAmcmVjdCwgJmNoLCAxLCBOVUxMICk7CgkJCUV4dFRleHRPdXQoIGhEQywgeCArIDEsIHkgLSAxLCBFVE9fQ0xJUFBFRCwgJnJlY3QsICZjaCwgMSwgTlVMTCApOwoJCQlFeHRUZXh0T3V0KCBoREMsIHggKyAxLCB5LCBFVE9fQ0xJUFBFRCwgJnJlY3QsICZjaCwgMSwgTlVMTCApOwoJCQlFeHRUZXh0T3V0KCBoREMsIHggKyAxLCB5ICsgMSwgRVRPX0NMSVBQRUQsICZyZWN0LCAmY2gsIDEsIE5VTEwgKTsKCQkJRXh0VGV4dE91dCggaERDLCB4LCB5ICsgMSwgRVRPX0NMSVBQRUQsICZyZWN0LCAmY2gsIDEsIE5VTEwgKTsKCQkJRXh0VGV4dE91dCggaERDLCB4IC0gMSwgeSArIDEsIEVUT19DTElQUEVELCAmcmVjdCwgJmNoLCAxLCBOVUxMICk7CgkJCUV4dFRleHRPdXQoIGhEQywgeCAtIDEsIHksIEVUT19DTElQUEVELCAmcmVjdCwgJmNoLCAxLCBOVUxMICk7CgkJCVNldFRleHRDb2xvciggaERDLCBSR0IoMjU1LCAwLCAwKSApOwoJCQlFeHRUZXh0T3V0KCBoREMsIHgsIHksIEVUT19DTElQUEVELCAmcmVjdCwgJmNoLCAxLCBOVUxMICk7CgkJCXgtLTsKCQkJeS0tOwoJCX0KCQllbHNlCgkJewoJCQlTZXRUZXh0Q29sb3IoIGhEQywgUkdCKDI1NSwgMCwgMCkgKTsKCQkJRXh0VGV4dE91dCggaERDLCB4LCB5LCBFVE9fQ0xJUFBFRCwgJnJlY3QsICZjaCwgMSwgTlVMTCApOwoJCX0KCgkJLy90dSBzcmMgKyBkc3QKCQltX2ZUZXhDb29yZHNbYyAtIDMyXVswXSA9IChmbG9hdCkoIHggKyAwIC0gbV9jaHJTcGFjaW5nICkgLyAoZmxvYXQpbV90ZXhXaWR0aDsKCQltX2ZUZXhDb29yZHNbYyAtIDMyXVsyXSA9IChmbG9hdCkoIHggKyBzaXplLmN4ICsgbV9jaHJTcGFjaW5nICkgLyAoZmxvYXQpbV90ZXhXaWR0aDsKCgkJLy90diBzcmMgKyBkc3QKCQltX2ZUZXhDb29yZHNbYyAtIDMyXVsxXSA9IChmbG9hdCkoIHkgKyAwICsgMCApIC8gKGZsb2F0KW1fdGV4SGVpZ2h0OwoJCW1fZlRleENvb3Jkc1tjIC0gMzJdWzNdID0gKGZsb2F0KSggeSArIHNpemUuY3kgKyAwICkgLyAoZmxvYXQpbV90ZXhIZWlnaHQ7CgoJCXggKz0gc2l6ZS5jeCArICggMiAqIG1fY2hyU3BhY2luZyApOwoJfQoKCUQzRExPQ0tFRF9SRUNUCWQzZGxyOwoJbV9wRDNEdGV4LT5Mb2NrUmVjdCggMCwgJmQzZGxyLCAwLCAwICk7CgoJQllURQkqcERzdFJvdyA9IChCWVRFICopZDNkbHIucEJpdHM7CglXT1JECSpwRHN0MTY7CgoJZm9yICggeSA9IDA7IHkgPCBtX3RleEhlaWdodDsgeSsrICkKCXsKCQlwRHN0MTYgPSAoV09SRCAqKXBEc3RSb3c7CgoJCWZvciAoIHggPSAwOyB4IDwgbV90ZXhXaWR0aDsgeCsrICkKCQl7CgkJCURXT1JECXBpeGVsID0gcEJpdG1hcEJpdHNbbV90ZXhXaWR0aCAqIHkgKyB4XTsKCQkJQllURQliQWxwaGEgPSAxNSAtICggKChCWVRFKSAocGl4ZWwgPj4gOCkpID4+IDQgKTsJLy8gZ3JlZW4gY2hhbm5lbAoJCQlCWVRFCWJWYWx1ZSA9ICggKEJZVEUpIChwaXhlbCA+PiAxNikgKSA+PiA0OwkJCS8vIHJlZCBjaGFubmVsCgkJCSpwRHN0MTYgPSAoIFdPUkQgKSAoIGJBbHBoYSA8PCAxMiApIHwgKCBiVmFsdWUgPDwgOCApIHwgKCBiVmFsdWUgPDwgNCApIHwgKCBiVmFsdWUgKTsKCQkJcERzdDE2Kys7CgkJfQoKCQlwRHN0Um93ICs9IGQzZGxyLlBpdGNoOwoJfQoKCW1fcEQzRHRleC0+VW5sb2NrUmVjdCggMCApOwoKCURlbGV0ZU9iamVjdCggaGJtQml0bWFwICk7CglEZWxldGVEQyggaERDICk7CglEZWxldGVPYmplY3QoIGhGb250ICk7CgoJbV9pc1JlYWR5ID0gdHJ1ZTsKCglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNERm9udDo6SW52YWxpZGF0ZSAoKQp7CgltX2lzUmVhZHkgPSBmYWxzZTsKCglTQUZFX1JFTEVBU0UoIG1fcEQzRHRleCApOwoJU0FGRV9SRUxFQVNFKCBtX3BEM0RidWYgKTsKCgkvL1NBRkVfUkVMRUFTRShtX3BEM0RzdGF0ZURyYXcpOwoJLy9TQUZFX1JFTEVBU0UobV9wRDNEc3RhdGVOb3JtKTsKCW1fcFJlbmRlci0+SW52YWxpZGF0ZSgpOwoKCUNEM0RCYXNlUmVuZGVyOjpJbnZhbGlkYXRlKCk7CglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNERm9udDo6UHJpbnQgKCBmbG9hdCB4LCBmbG9hdCB5LCBEV09SRCBjb2xvciwgY29uc3QgY2hhciAqc3pUZXh0LCBib29sIHRleHRjb2xvcmluZyApCnsKCWlmICggIW1faXNSZWFkeSApCgkJcmV0dXJuIEVfRkFJTDsKCglmbG9hdAlzdHJXaWR0aCA9IERyYXdMZW5ndGgoIHN6VGV4dCApOwoKCXggLT0gKGZsb2F0KW1fY2hyU3BhY2luZzsKCglpZiAoIEZBSUxFRCh0aGlzLT5CZWdpblJlbmRlcigpKSApCgkJcmV0dXJuIEVfRkFJTDsKCgkvLwoJLy9tX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQ09MT1JPUCwgRDNEVE9QX1NFTEVDVEFSRzIgKTsKCS8vbV9wRDNEZGV2LT5TZXRUZXh0dXJlU3RhZ2VTdGF0ZSggMCwgRDNEVFNTX0FMUEhBT1AsIEQzRFRPUF9TRUxFQ1RBUkcyICk7CgoJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfQ0xJUFBJTkcsIGZhbHNlICk7CgltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlICggRDNEUlNfWkVOQUJMRSwgZmFsc2UgKTsKCgkvLwoKCURXT1JECWZ2ZjsKCW1fcEQzRGRldi0+R2V0RlZGKCAmZnZmICk7CgltX3BEM0RkZXYtPlNldEZWRiggRDNERlZGX0JJVE1BUEZPTlQgKTsKCW1fcEQzRGRldi0+U2V0VGV4dHVyZSggMCwgbV9wRDNEdGV4ICk7CgltX3BEM0RkZXYtPlNldFN0cmVhbVNvdXJjZSggMCwgbV9wRDNEYnVmLCAwLCBzaXplb2YoZDNkdmVydGV4X3MpICk7CgoJRFdPUkQgY3VycmVudGNvbG9yID0gY29sb3I7Cglib29sIEdldHRpbmdDb2xvciA9IGZhbHNlOwoKCXdoaWxlICggKnN6VGV4dCApCgl7CgkJVUlOVAkJdXNlZFRyaWFuZ2xlcyA9IDA7CgkJZDNkdmVydGV4X3MgKnBWZXJ0ZXg7CgoJCWlmICggRkFJTEVEKG1fcEQzRGJ1Zi0+TG9jaygwLCAwLCAodm9pZCAqKikgJnBWZXJ0ZXgsIEQzRExPQ0tfRElTQ0FSRCkpICkKCQl7CgkJCW1fcEQzRGRldi0+U2V0RlZGKCBmdmYgKTsKCQkJdGhpcy0+RW5kUmVuZGVyKCk7CgkJCXJldHVybiBFX0ZBSUw7CgkJfQoKCgkJZm9yICggOyAqc3pUZXh0OyBzelRleHQrKyApCgkJewkKCQkJaWYodGV4dGNvbG9yaW5nKQoJCQl7CgkJCQlpZigqc3pUZXh0ID09ICd7JykKCQkJCXsKCQkJCQljaGFyIGNjb2xvcls5XSA9IHswfTsKCQkJCQl1bnNpZ25lZCBsb25nIHRlbXBjb2xvciA9IDA7CgkJCQkJZm9yKHVuc2lnbmVkIGludCBpID0gMTsgaSA8IDEwOyArK2kpCgkJCQkJewoJCQkJCQlpZigqKHN6VGV4dCtpKSkKCQkJCQkJewoJCQkJCQkJaWYoaSA9PSA5KQoJCQkJCQkJewoJCQkJCQkJCWlmKCooc3pUZXh0KyhpKSkgIT0gJ30nKQoJCQkJCQkJCXsKCQkJCQkJCQkJYnJlYWs7CgkJCQkJCQkJfQoJCQkJCQkJCWlmKHNzY2FuZihjY29sb3IsICIleCIsICZ0ZW1wY29sb3IpICE9IDEpCgkJCQkJCQkJewoJCQkJCQkJCQlicmVhazsKCQkJCQkJCQl9CgkJCQkJCQkJY3VycmVudGNvbG9yID0gdGVtcGNvbG9yOwoJCQkJCQkJCXN6VGV4dCs9OTsKCQkJCQkJCQlHZXR0aW5nQ29sb3IgPSB0cnVlOwoJCQkJCQkJCWJyZWFrOwoJCQkJCQkJfQoJCQkJCQkJY2NvbG9yW2ktMV0gPSAqKHN6VGV4dCtpKTsKCQkJCQkJfQoJCQkJCQllbHNlCgkJCQkJCXsKCQkJCQkJCWJyZWFrOwoJCQkJCQl9CgkJCQkJfQoJCQkJfQoJCQl9CgkJCWlmKEdldHRpbmdDb2xvcikKCQkJewoJCQkJR2V0dGluZ0NvbG9yID0gZmFsc2U7CgkJCQljb250aW51ZTsKCQkJfQoJCQlpbnQgYyA9ICoodW5zaWduZWQgY2hhciAqKXN6VGV4dCAtIDMyOwoJCQlpZiAoICEoYyA+PSAwICYmIGMgPCAyMjQpICkKCQkJCWNvbnRpbnVlOwoKCQkJZmxvYXQJdHgxID0gbV9mVGV4Q29vcmRzW2NdWzBdOwoJCQlmbG9hdAl0eDIgPSBtX2ZUZXhDb29yZHNbY11bMl07CgkJCWZsb2F0CXR5MSA9IG1fZlRleENvb3Jkc1tjXVsxXTsKCQkJZmxvYXQJdHkyID0gbV9mVGV4Q29vcmRzW2NdWzNdOwoJCQlmbG9hdAl3ID0gKCB0eDIgLSB0eDEgKSAqIG1fdGV4V2lkdGg7CgkJCWZsb2F0CWggPSAoIHR5MiAtIHR5MSApICogbV90ZXhIZWlnaHQ7CgoJCQkqcFZlcnRleCsrID0gSW5pdDJEVmVydGV4KCB4IC0gMC41ZiwgeSAtIDAuNWYsIGN1cnJlbnRjb2xvciwgdHgxLCB0eTEgKTsJCQkvL3RvcGxlZnQKCQkJKnBWZXJ0ZXgrKyA9IEluaXQyRFZlcnRleCggeCArIHcgLSAwLjVmLCB5IC0gMC41ZiwgY3VycmVudGNvbG9yLCB0eDIsIHR5MSApOwkJLy90b3ByaWdodAoJCQkqcFZlcnRleCsrID0gSW5pdDJEVmVydGV4KCB4IC0gMC41ZiwgeSArIGggLSAwLjVmLCBjdXJyZW50Y29sb3IsIHR4MSwgdHkyICk7CQkvL2JvdHRvbWxlZnQKCQkJKnBWZXJ0ZXgrKyA9IEluaXQyRFZlcnRleCggeCArIHcgLSAwLjVmLCB5IC0gMC41ZiwgY3VycmVudGNvbG9yLCB0eDIsIHR5MSApOwkJLy90b3ByaWdodAoJCQkqcFZlcnRleCsrID0gSW5pdDJEVmVydGV4KCB4ICsgdyAtIDAuNWYsIHkgKyBoIC0gMC41ZiwgY3VycmVudGNvbG9yLCB0eDIsIHR5MiApOwkvL2JvdHRvbXJpZ2h0CgkJCSpwVmVydGV4KysgPSBJbml0MkRWZXJ0ZXgoIHggLSAwLjVmLCB5ICsgaCAtIDAuNWYsIGN1cnJlbnRjb2xvciwgdHgxLCB0eTIgKTsJCS8vYm90dG9tbGVmdAoJCQlpZiAoIG1fZHdDcmVhdGVGbGFncyAmIEZDUl9CT1JERVIgKQoJCQkJdyAtPSAyLjBmOwoKCQkJeCArPSB3IC0gKCBtX2NoclNwYWNpbmcgKiAyICk7CgoJCQl1c2VkVHJpYW5nbGVzICs9IDI7CgkJCWlmICggdXNlZFRyaWFuZ2xlcyA+PSBtX21heFRyaWFuZ2xlcyApCgkJCQlicmVhazsKCQl9CgoJCWlmICggdXNlZFRyaWFuZ2xlcyA+IDAgKQoJCXsKCQkJbV9wRDNEYnVmLT5VbmxvY2soKTsKCQkJbV9wRDNEZGV2LT5EcmF3UHJpbWl0aXZlKCBEM0RQVF9UUklBTkdMRUxJU1QsIDAsIHVzZWRUcmlhbmdsZXMgKTsKCQl9Cgl9CgoJbV9wRDNEZGV2LT5TZXRGVkYoIGZ2ZiApOwoKCS8vCgkvL21fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19DT0xPUk9QLCBEM0RUT1BfTU9EVUxBVEUgKTsKCS8vbV9wRDNEZGV2LT5TZXRUZXh0dXJlU3RhZ2VTdGF0ZSggMCwgRDNEVFNTX0FMUEhBT1AsIEQzRFRPUF9NT0RVTEFURSApOwoJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSAoIEQzRFJTX1pFTkFCTEUsIHRydWUgKTsKCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0NMSVBQSU5HLCB0cnVlICk7CgkvLwoJdGhpcy0+RW5kUmVuZGVyKCk7CgoJcmV0dXJuIFNfT0s7Cn0KCkhSRVNVTFQgQ0QzREZvbnQ6OlByaW50U2hhZG93ICggZmxvYXQgeCwgZmxvYXQgeSwgRFdPUkQgY29sb3IsIGNvbnN0IGNoYXIgKnN6VGV4dCApCnsKCVByaW50KCB4LCB5LCBjb2xvciwgc3pUZXh0ICk7CgoJcmV0dXJuIFNfT0s7Cn0KCmZsb2F0IENEM0RGb250OjpEcmF3TGVuZ3RoICggY29uc3QgY2hhciAqc3pUZXh0ICkgY29uc3QKewoJZmxvYXQJbGVuID0gMC4wZjsKCWZsb2F0CXN1YiA9ICggbV9kd0NyZWF0ZUZsYWdzICYgRkNSX0JPUkRFUiApID8gMi4wZiA6IDAuMGY7CgoJZm9yICggY29uc3QgY2hhciAqcCA9IHN6VGV4dDsgKnA7IHArKyApCgl7CgkJaW50IGMgPSAqKHVuc2lnbmVkIGNoYXIgKilwIC0gMzI7CgkJaWYgKCBjID49IDAgJiYgYyA8IDIyNCApCgkJCWxlbiArPSAoIChtX2ZUZXhDb29yZHNbY11bMl0gLSBtX2ZUZXhDb29yZHNbY11bMF0pICogbV90ZXhXaWR0aCAtIHN1YiApIC0gbV9jaHJTcGFjaW5nICogMjsKCX0KCglyZXR1cm4gbGVuOwp9CgpDRDNEUmVuZGVyOjpDRDNEUmVuZGVyICggaW50IG51bVZlcnRpY2VzICkKewoJbV9jYW5SZW5kZXIgPSBmYWxzZTsKCgltX3BEM0RidWYgPSBOVUxMOwoJbV9wVmVydGV4ID0gTlVMTDsKCgltX2NvbG9yID0gMDsKCW1fdHUgPSAwLjBmOwoJbV90diA9IDAuMGY7CgltX3RleHR1cmUgPSBOVUxMOwoKCW1fbWF4VmVydGV4ID0gbnVtVmVydGljZXM7CgltX2N1clZlcnRleCA9IDA7Cn0KCkNEM0RSZW5kZXI6On5DRDNEUmVuZGVyICgpCnsKCUludmFsaWRhdGUoKTsKfQoKSFJFU1VMVCBDRDNEUmVuZGVyOjpJbml0aWFsaXplICggSURpcmVjdDNERGV2aWNlOSAqcEQzRGRldiApCnsKCWlmICggIW1fY2FuUmVuZGVyICkKCXsKCQlpZiAoIEZBSUxFRChDRDNEQmFzZVJlbmRlcjo6SW5pdGlhbGl6ZShwRDNEZGV2KSkgKQoJCQlyZXR1cm4gRV9GQUlMOwoJCWlmICggRkFJTEVEKG1fcEQzRGRldi0+Q3JlYXRlVmVydGV4QnVmZmVyKG1fbWF4VmVydGV4ICogc2l6ZW9mKGQzZHZlcnRleF9zKSwKCQkJCQkgRDNEVVNBR0VfV1JJVEVPTkxZIHwgRDNEVVNBR0VfRFlOQU1JQywgMCwgRDNEUE9PTF9ERUZBVUxULCAmbV9wRDNEYnVmLCBOVUxMKSkgKQoJCQlyZXR1cm4gRV9GQUlMOwoKCQltX2NhblJlbmRlciA9IHRydWU7Cgl9CgoJcmV0dXJuIFNfT0s7Cn0KCkhSRVNVTFQgQ0QzRFJlbmRlcjo6SW52YWxpZGF0ZSAoKQp7CglTQUZFX1JFTEVBU0UoIG1fcEQzRGJ1ZiApOwoJU0FGRV9SRUxFQVNFKCBtX3RleHR1cmUgKTsKCS8vbV9wVmVydGV4ID0gTlVMTDsKCgkvL1NBRkVfUkVMRUFTRShtX3BEM0RzdGF0ZURyYXcpOwoJLy9TQUZFX1JFTEVBU0UobV9wRDNEc3RhdGVOb3JtKTsKCS8vQ0QzREJhc2VSZW5kZXI6OkludmFsaWRhdGUoKTsKCS8vbV9jYW5SZW5kZXIgPSBmYWxzZTsKCglyZXR1cm4gU19PSzsKfQoKSFJFU1VMVCBDRDNEUmVuZGVyOjpCZWdpbiAoIEQzRFBSSU1JVElWRVRZUEUgcHJpbVR5cGUgKQp7CglpZiAoICFtX2NhblJlbmRlciApCgkJcmV0dXJuIEVfRkFJTDsKCglpZiAoIG1fcFZlcnRleCAhPSBOVUxMICkKCQlyZXR1cm4gRV9GQUlMOwoKCWlmICggRkFJTEVEKG1fcEQzRGJ1Zi0+TG9jaygwLCAwLCAodm9pZCAqKikgJm1fcFZlcnRleCwgRDNETE9DS19ESVNDQVJEKSkgKQoJCXJldHVybiBFX0ZBSUw7CgoJbV9wcmltVHlwZSA9IHByaW1UeXBlOwoKCXJldHVybiBTX09LOwp9CgpIUkVTVUxUIENEM0RSZW5kZXI6OkVuZCAoKQp7CglpbnQgbnVtUHJpbXM7CgoJbV9wVmVydGV4ID0gTlVMTDsKCglpZiAoICFtX2NhblJlbmRlciApCgl7CgkJbV9jdXJWZXJ0ZXggPSAwOwoJCXJldHVybiBFX0ZBSUw7Cgl9CgoJaWYgKCBGQUlMRUQoQ0QzREJhc2VSZW5kZXI6OkJlZ2luUmVuZGVyKCkpICkKCQlyZXR1cm4gRV9GQUlMOwoKCXN3aXRjaCAoIG1fcHJpbVR5cGUgKQoJewoJY2FzZSBEM0RQVF9QT0lOVExJU1Q6CgkJbnVtUHJpbXMgPSBtX2N1clZlcnRleDsKCQlicmVhazsKCgljYXNlIEQzRFBUX0xJTkVMSVNUOgoJCW51bVByaW1zID0gbV9jdXJWZXJ0ZXggLyAyOwoJCWJyZWFrOwoKCWNhc2UgRDNEUFRfTElORVNUUklQOgoJCW51bVByaW1zID0gbV9jdXJWZXJ0ZXggLSAxOwoJCWJyZWFrOwoKCWNhc2UgRDNEUFRfVFJJQU5HTEVMSVNUOgoJCW51bVByaW1zID0gbV9jdXJWZXJ0ZXggLyAzOwoJCWJyZWFrOwoKCWNhc2UgRDNEUFRfVFJJQU5HTEVTVFJJUDoKCWNhc2UgRDNEUFRfVFJJQU5HTEVGQU46CgkJbnVtUHJpbXMgPSBtX2N1clZlcnRleCAtIDI7CgkJYnJlYWs7CgoJZGVmYXVsdDoKCQludW1QcmltcyA9IDA7CgkJYnJlYWs7Cgl9CgoJbV9jdXJWZXJ0ZXggPSAwOwoKCWlmICggbnVtUHJpbXMgPiAwICkKCXsKCQltX3BEM0RidWYtPlVubG9jaygpOwoKCQlEV09SRAlmdmY7CgkJbV9wRDNEZGV2LT5HZXRGVkYoICZmdmYgKTsKCgkJaWYgKCBtX3RleHR1cmUgPT0gTlVMTCApCgkJewoJCQltX3BEM0RkZXYtPlNldEZWRiggRDNERlZGX1BSSU1JVElWRVMgKTsKCQkJbV9wRDNEZGV2LT5TZXRUZXh0dXJlKCAwLCBOVUxMICk7CgkJfQoJCWVsc2UKCQl7CgkJCW1fcEQzRGRldi0+U2V0RlZGKCBEM0RGVkZfQklUTUFQRk9OVCApOwoJCQltX3BEM0RkZXYtPlNldFRleHR1cmUoIDAsIG1fdGV4dHVyZSApOwoJCX0KCgkJbV9wRDNEZGV2LT5TZXRTdHJlYW1Tb3VyY2UoIDAsIG1fcEQzRGJ1ZiwgMCwgc2l6ZW9mKGQzZHZlcnRleF9zKSApOwoKCQltX3BEM0RkZXYtPkRyYXdQcmltaXRpdmUoIG1fcHJpbVR5cGUsIDAsIG51bVByaW1zICk7CgoJCW1fcEQzRGRldi0+U2V0RlZGKCBmdmYgKTsKCX0KCglDRDNEQmFzZVJlbmRlcjo6RW5kUmVuZGVyKCk7CgoJcmV0dXJuIFNfT0s7Cn0KCkhSRVNVTFQgQ0QzRFJlbmRlcjo6RDNEQ29sb3IgKCBEV09SRCBjb2xvciApCnsKCW1fY29sb3IgPSBjb2xvcjsKCXJldHVybiBtX2NhblJlbmRlciA/IFNfT0sgOiBFX0ZBSUw7CglyZXR1cm4gU19PSzsKfQoKdm9pZCBDRDNEUmVuZGVyOjpEM0RCaW5kVGV4dHVyZSAoIElEaXJlY3QzRFRleHR1cmU5ICp0ZXh0dXJlICkKewoJbV90ZXh0dXJlID0gdGV4dHVyZTsKfQoKdm9pZCBDRDNEUmVuZGVyOjpEM0RUZXhDb29yZDJmICggZmxvYXQgdSwgZmxvYXQgdiApCnsKCW1fdHUgPSB1OwoJbV90diA9IHY7Cn0KCkhSRVNVTFQgQ0QzRFJlbmRlcjo6RDNEVmVydGV4MmYgKCBmbG9hdCB4LCBmbG9hdCB5ICkKewoJaWYgKCBtX2NhblJlbmRlciAmJiBtX3BWZXJ0ZXggJiYgKyttX2N1clZlcnRleCA8IG1fbWF4VmVydGV4ICkKCQkqbV9wVmVydGV4KysgPSBJbml0MkRWZXJ0ZXgoIHgsIHksIG1fY29sb3IsIG1fdHUsIG1fdHYgKTsKCWVsc2UKCQlyZXR1cm4gRV9GQUlMOwoKCXJldHVybiBTX09LOwp9Cgp2b2lkIENEM0RSZW5kZXI6OkQzRFRleFF1YWQgKCBmbG9hdCBzeCwgZmxvYXQgc3ksIGZsb2F0IGV4LCBmbG9hdCBleSwgZmxvYXQgc3UsIGZsb2F0IHN2LCBmbG9hdCBldSwgZmxvYXQgZXYgKQp7CglpZiAoIFNVQ0NFRURFRChCZWdpbihEM0RQVF9UUklBTkdMRUxJU1QpKSApCgl7CgkJRDNEQ29sb3IoIEQzRENPTE9SX1hSR0IoMjU1LCAyNTUsIDI1NSkgKTsKCQlEM0RUZXhDb29yZDJmKCBzdSwgc3YgKTsKCQlEM0RWZXJ0ZXgyZiggc3gsIHN5ICk7CgkJRDNEVGV4Q29vcmQyZiggZXUsIHN2ICk7CgkJRDNEVmVydGV4MmYoIGV4LCBzeSApOwoJCUQzRFRleENvb3JkMmYoIHN1LCBldiApOwoJCUQzRFZlcnRleDJmKCBzeCwgZXkgKTsKCgkJRDNEVGV4Q29vcmQyZiggc3UsIGV2ICk7CgkJRDNEVmVydGV4MmYoIHN4LCBleSApOwoJCUQzRFRleENvb3JkMmYoIGV1LCBzdiApOwoJCUQzRFZlcnRleDJmKCBleCwgc3kgKTsKCQlEM0RUZXhDb29yZDJmKCBldSwgZXYgKTsKCQlEM0RWZXJ0ZXgyZiggZXgsIGV5ICk7CgkJRW5kKCk7Cgl9Cn0KCnZvaWQgQ0QzRFJlbmRlcjo6RDNEQm94ICggZmxvYXQgeCwgZmxvYXQgeSwgZmxvYXQgdywgZmxvYXQgaCwgRDNEQ09MT1IgY29sb3IgKQp7CgkvL21fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19DT0xPUk9QLCBEM0RUT1BfU0VMRUNUQVJHMiApOwoJLy9tX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQUxQSEFPUCwgRDNEVE9QX1NFTEVDVEFSRzIgKTsKCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUoIEQzRFJTX0NMSVBQSU5HLCBmYWxzZSApOwoJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSAoIEQzRFJTX1pFTkFCTEUsIGZhbHNlICk7CglpZiAoIFNVQ0NFRURFRChCZWdpbihEM0RQVF9UUklBTkdMRUxJU1QpKSApCgl7CgkJRDNEQ29sb3IoIGNvbG9yICk7CgkJRDNEVmVydGV4MmYoIHgsIHkgKTsKCQlEM0RWZXJ0ZXgyZiggeCArIHcsIHkgKTsKCQlEM0RWZXJ0ZXgyZiggeCwgeSArIGggKTsKCQlEM0RWZXJ0ZXgyZiggeCwgeSArIGggKTsKCQlEM0RWZXJ0ZXgyZiggeCArIHcsIHkgKTsKCQlEM0RWZXJ0ZXgyZiggeCArIHcsIHkgKyBoICk7CgkJRW5kKCk7Cgl9CgkvLyByZXNldCBzdGF0ZXMKCS8vbV9wRDNEZGV2LT5TZXRUZXh0dXJlU3RhZ2VTdGF0ZSggMCwgRDNEVFNTX0NPTE9ST1AsIEQzRFRPUF9NT0RVTEFURSApOwoJLy9tX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQUxQSEFPUCwgRDNEVE9QX01PRFVMQVRFICk7CgltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlICggRDNEUlNfWkVOQUJMRSwgdHJ1ZSApOwoJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfQ0xJUFBJTkcsIHRydWUgKTsKfQoKdm9pZCBDRDNEUmVuZGVyOjpEM0RCb3hpICggaW50IHgsIGludCB5LCBpbnQgdywgaW50IGgsIEQzRENPTE9SIGNvbG9yLCBpbnQgbWF4VyApCnsKCWlmICggbWF4VyApCgl7CgkJaWYgKCB3ID49IG1heFcgKQoJCQkoIHcgPSBtYXhXICk7CgkJRDNEQm94KCAoZmxvYXQpeCwgKGZsb2F0KXksIChmbG9hdCl3LCAoZmxvYXQpaCwgY29sb3IgKTsKCX0KCWVsc2UKCXsKCQlEM0RCb3goIChmbG9hdCl4LCAoZmxvYXQpeSwgKGZsb2F0KXcsIChmbG9hdCloLCBjb2xvciApOwoJfQp9Cgp2b2lkIENEM0RSZW5kZXI6OkQzREJveEJvcmRlciAoIGZsb2F0IHgsIGZsb2F0IHksIGZsb2F0IHcsIGZsb2F0IGgsIEQzRENPTE9SIGJvcmRlcl9jb2xvciwgRDNEQ09MT1IgY29sb3IgKQp7CglEM0RCb3goIHgsIHksIHcsIDEuMGYsIGJvcmRlcl9jb2xvciApOwoJRDNEQm94KCB4ICsgdywgeSwgMS4wZiwgaCwgYm9yZGVyX2NvbG9yICk7CglEM0RCb3goIHgsIHksIDEuMGYsIGgsIGJvcmRlcl9jb2xvciApOwoJRDNEQm94KCB4LCB5ICsgaCwgdywgMS4wZiwgYm9yZGVyX2NvbG9yICk7CglEM0RCb3goIHggKyAxLjBmLCB5ICsgMS4wZiwgdyAtIDEuMGYsIGggLSAxLjBmLCBjb2xvciApOwp9Cgp2b2lkIENEM0RSZW5kZXI6OkQzREJveEJvcmRlcmkgKCBpbnQgeCwgaW50IHksIGludCB3LCBpbnQgaCwgRDNEQ09MT1IgYm9yZGVyX2NvbG9yLCBEM0RDT0xPUiBjb2xvciApCnsKCUQzREJveEJvcmRlciggKGZsb2F0KXgsIChmbG9hdCl5LCAoZmxvYXQpdywgKGZsb2F0KWgsIGJvcmRlcl9jb2xvciwgY29sb3IgKTsKfQoKYm9vbCBDRDNEUmVuZGVyOjpEcmF3TGluZSAoIGNvbnN0IEQzRFhWRUNUT1IzICZhLCBjb25zdCBEM0RYVkVDVE9SMyAmYiwgRFdPUkQgZHdDb2xvciApCnsKCWlmICggRkFJTEVEKENEM0RCYXNlUmVuZGVyOjpCZWdpblJlbmRlcigpKSApCgkJcmV0dXJuIGZhbHNlOwoKCS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCS8vIE1ha2Ugc3VyZSB3ZSBoYXZlIGEgdmFsaWQgdmVydGV4IGJ1ZmZlci4KCWlmICggbV9wRDNEYnVmID09IE5VTEwgKQoJewoJCXJldHVybiBmYWxzZTsKCX0KCgltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQ09MT1JPUCwgRDNEVE9QX1NFTEVDVEFSRzIgKTsKCW1fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19BTFBIQU9QLCBEM0RUT1BfU0VMRUNUQVJHMiApOwoJLy9tX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQ09MT1JBUkcyLCBEM0RUQV9ESUZGVVNFICk7CgkvL21fcEQzRGRldi0+U2V0VGV4dHVyZVN0YWdlU3RhdGUoIDAsIEQzRFRTU19BTFBIQUFSRzIsIEQzRFRBX0RJRkZVU0UgKTsKCgltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlKCBEM0RSU19DTElQUElORywgZmFsc2UgKTsKCW1fcEQzRGRldi0+U2V0UmVuZGVyU3RhdGUgKCBEM0RSU19aRU5BQkxFLCBmYWxzZSApOwoJLy9tX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlICggRDNEUlNfTElHSFRJTkcsIGZhbHNlICk7CglEM0RMVkVSVEVYCWxpbmVMaXN0WzJdOwoKCS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgkvLyBMb2NrIHRoZSB2ZXJ0ZXggYnVmZmVyIGFuZCBjb3B5IGluIHRoZSB2ZXJ0cy4KCW1fcEQzRGJ1Zi0+TG9jayggMCwgMCwgKHZvaWQgKiopICZsaW5lTGlzdCwgRDNETE9DS19ESVNDQVJEIHwgRDNETE9DS19OT1NZU0xPQ0sgKTsgLy8gZmxvZ3M6IEQzRExPQ0tfTk9TWVNMT0NLLCBEM0RMT0NLX0RJU0NBUkQKCXsKCQlsaW5lTGlzdFswXS54ID0gYS54OwoJCWxpbmVMaXN0WzBdLnkgPSBhLnk7CgkJbGluZUxpc3RbMF0ueiA9IGEuejsKCQlsaW5lTGlzdFswXS5jb2xvciA9IGR3Q29sb3I7CgkJbGluZUxpc3RbMF0uc3BlY3VsYXIgPSBkd0NvbG9yOwoKCQlsaW5lTGlzdFsxXS54ID0gYi54OwoJCWxpbmVMaXN0WzFdLnkgPSBiLnk7CgkJbGluZUxpc3RbMV0ueiA9IGIuejsKCQlsaW5lTGlzdFsxXS5jb2xvciA9IGR3Q29sb3I7CgkJbGluZUxpc3RbMV0uc3BlY3VsYXIgPSBkd0NvbG9yOwoJfQoKCW1fcEQzRGJ1Zi0+VW5sb2NrKCk7CgoJLy8gc3RvcmUgRlZGIHRvIHJlc3RvcmUgb3JpZ2luYWwgYXQgdGhlIGVuZCBvZiB0aGlzIGZ1bmN0aW9uCglEV09SRAkJZnZmOwoJbV9wRDNEZGV2LT5HZXRGVkYoICZmdmYgKTsKCW1fcEQzRGRldi0+U2V0RlZGKCBEM0RGVkZfTFZFUlRFWCApOwoJLy9tX3BEM0RkZXYtPlNldEZWRiggRDNERlZGX1BSSU1JVElWRVMgKTsKCgkvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vCgkvLyBEcmF3IQoJbV9wRDNEZGV2LT5EcmF3UHJpbWl0aXZlVVAoIEQzRFBUX0xJTkVTVFJJUCwgMSwgbGluZUxpc3QsIHNpemVvZihsaW5lTGlzdCkgLyAyICk7CgoJLy8gcmVzZXQgc3RhdGVzCgltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQ09MT1JPUCwgRDNEVE9QX01PRFVMQVRFICk7CgltX3BEM0RkZXYtPlNldFRleHR1cmVTdGFnZVN0YXRlKCAwLCBEM0RUU1NfQUxQSEFPUCwgRDNEVE9QX01PRFVMQVRFICk7CgltX3BEM0RkZXYtPlNldFJlbmRlclN0YXRlICggRDNEUlNfWkVOQUJMRSwgdHJ1ZSApOwoJbV9wRDNEZGV2LT5TZXRSZW5kZXJTdGF0ZSggRDNEUlNfQ0xJUFBJTkcsIHRydWUgKTsKCgkvLyByZXN0b3JlIEZWRgoJbV9wRDNEZGV2LT5TZXRGVkYoIGZ2ZiApOwoKCUNEM0RCYXNlUmVuZGVyOjpFbmRSZW5kZXIoKTsKCglyZXR1cm4gdHJ1ZTsKfQo=